├── .gitignore ├── APLCommon.pri ├── APLDockWidget.cpp ├── APLDockWidget.h ├── APLLoggingCategory.cpp ├── APLLoggingCategory.h ├── APLSetup.pri ├── ArduPilotLog.pro ├── ArduPilotLog.udb ├── ReadMe.md ├── aplresources.qrc ├── ardupilotlog.qrc ├── chibios log.bin ├── conf ├── 001_ATT_Roll_Ang.conf ├── 002_ATT_Roll_AngVel.conf ├── 003_ATT_Roll_FeedFoward.conf ├── 004_ATT_Roll_LowpassD.conf ├── 005_ATT_Roll_PID.conf ├── 006_ATT_Pitch_Ang.conf ├── 007_ATT_Pitch_AngVel.conf ├── 008_ATT_Pitch_FeedFoward.conf ├── 009_ATT_Pitch_LowpassD.conf ├── 010_ATT_Pitch_PID.conf ├── 011_ATT_Yaw_Ang.conf ├── 012_ATT_Yaw_AngVel.conf ├── 013_ATT_Yaw_FeedFoward.conf ├── 014_ATT_Yaw_LowpassD.conf ├── 015_ATT_Yaw_PID.conf ├── 016_ATT_Yaw_LowpassIn.conf ├── 017_TILT_Ang_ErrZ.conf ├── 018_Yaw_out_off_control.conf ├── 019_RC_Failsafe.conf ├── 020_VD_Z_RC.conf ├── 021_PSC_POS_Z.conf ├── 022_PSC_VEL_Z.conf ├── 023_PSC_ACC_Z.conf ├── 024_BARO_IMU.conf ├── 025_PIDA_D_Lowpass.conf ├── 026_PIDA_E_Lowpass.conf ├── 027_PSC_VEL_FF.conf ├── 028_FLOW_X.conf ├── 029_FLOW_Y.conf ├── 030_RPYT.conf ├── 031_ATT_Roll_LowpassT.conf ├── 032_ATT_Roll_LowpassE.conf └── ReadMe.md ├── deploy ├── ardupilotlog-start.sh └── ardupilotlog.desktop ├── doc └── compile.md ├── gitlab.yml ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── matlab ├── APMBinaryLog.m ├── FSMAnalysis.m ├── ReadMe.md └── char2cell.m ├── qcustomplot.cpp ├── qcustomplot.h ├── resources └── icons │ ├── a01.ico │ ├── a02.ico │ ├── a03.ico │ ├── a04.ico │ ├── a05.ico │ ├── a06.ico │ ├── a07.ico │ ├── a08.ico │ ├── a09.ico │ ├── a10.ico │ ├── a11.ico │ ├── a12.ico │ ├── a13.ico │ ├── a14.ico │ ├── a15.ico │ ├── ardupilotlog.ico │ └── ardupilotlog.png └── src ├── APLDB.cpp ├── APLDB.h ├── APLQmlWidgetHolder.cpp ├── APLQmlWidgetHolder.h ├── APLQmlWidgetHolder.ui ├── APLRead.cpp ├── APLRead.h ├── APLReadConf.cpp ├── APLReadConf.h ├── AutoResize.qml ├── DataAnalyze.h ├── DataAnalyze.qml ├── DataAnalyzeController.cpp ├── DataAnalyzeController.h ├── Dialog.cpp ├── Dialog.h ├── DialogLoad.cpp ├── DialogLoad.h └── LogStructure.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.user -------------------------------------------------------------------------------- /APLCommon.pri: -------------------------------------------------------------------------------- 1 | linux { 2 | linux-g++ | linux-g++-64 | linux-g++-32 | linux-clang { 3 | message("Linux build") 4 | CONFIG += LinuxBuild 5 | DEFINES += __STDC_LIMIT_MACROS 6 | DEFINES += PACKED=/**/ 7 | linux-clang { 8 | message("Linux clang") 9 | QMAKE_CXXFLAGS += -Qunused-arguments -fcolor-diagnostics 10 | } 11 | } else : linux-rasp-pi2-g++ { 12 | message("Linux R-Pi2 build") 13 | CONFIG += LinuxBuild 14 | DEFINES += __STDC_LIMIT_MACROS __rasp_pi2__ 15 | } else : android-g++ { 16 | CONFIG += AndroidBuild MobileBuild 17 | DEFINES += __android__ 18 | DEFINES += __STDC_LIMIT_MACROS 19 | DEFINES += APL_ENABLE_BLUETOOTH 20 | target.path = $$DESTDIR 21 | equals(ANDROID_TARGET_ARCH, x86) { 22 | CONFIG += Androidx86Build 23 | DEFINES += __androidx86__ 24 | message("Android x86 build") 25 | } else { 26 | message("Android Arm build") 27 | } 28 | } else { 29 | error("Unsuported Linux toolchain, only GCC 32- or 64-bit is supported") 30 | } 31 | } else : win32 { 32 | win32-msvc2010 | win32-msvc2012 | win32-msvc2013 | win32-msvc2015 { 33 | message("Windows build") 34 | CONFIG += WindowsBuild 35 | DEFINES += __STDC_LIMIT_MACROS 36 | DEFINES += PACKED=/**/ 37 | } else { 38 | DEFINES += PACKED=/**/ 39 | #error("Unsupported Windows toolchain, only Visual Studio 2010, 2012, and 2013 are supported") 40 | } 41 | } else : macx { 42 | macx-clang | macx-llvm { 43 | message("Mac build") 44 | CONFIG += MacBuild 45 | DEFINES += __macos__ 46 | CONFIG += x86_64 47 | CONFIG -= x86 48 | equals(QT_MAJOR_VERSION, 5) | greaterThan(QT_MINOR_VERSION, 5) { 49 | QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 50 | } else { 51 | QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6 52 | } 53 | #-- Not forcing anything. Let qmake find the latest, installed SDK. 54 | #QMAKE_MAC_SDK = macosx10.12 55 | QMAKE_CXXFLAGS += -fvisibility=hidden 56 | } else { 57 | error("Unsupported Mac toolchain, only 64-bit LLVM+clang is supported") 58 | } 59 | } else : ios { 60 | !equals(QT_MAJOR_VERSION, 5) | !greaterThan(QT_MINOR_VERSION, 4) { 61 | error("Unsupported Qt version, 5.5.x or greater is required for iOS") 62 | } 63 | message("iOS build") 64 | CONFIG += iOSBuild MobileBuild app_bundle NoSerialBuild 65 | CONFIG -= bitcode 66 | DEFINES += __ios__ 67 | DEFINES += APL_NO_GOOGLE_MAPS 68 | DEFINES += NO_SERIAL_LINK 69 | DEFINES += APL_DISABLE_UVC 70 | QMAKE_IOS_DEPLOYMENT_TARGET = 8.0 71 | QMAKE_IOS_TARGETED_DEVICE_FAMILY = 1,2 # Universal 72 | QMAKE_LFLAGS += -Wl,-no_pie 73 | } else { 74 | error("Unsupported build platform, only Linux, Windows, Android and Mac (Mac OS and iOS) are supported") 75 | } 76 | 77 | # Enable ccache where we can 78 | linux|macx|ios { 79 | system(which ccache) { 80 | message("Found ccache, enabling") 81 | !ios { 82 | QMAKE_CXX = ccache $$QMAKE_CXX 83 | QMAKE_CC = ccache $$QMAKE_CC 84 | } else { 85 | QMAKE_CXX = $$PWD/tools/iosccachecc.sh 86 | QMAKE_CC = $$PWD/tools/iosccachecxx.sh 87 | } 88 | } 89 | } 90 | 91 | MobileBuild { 92 | DEFINES += __mobile__ 93 | } 94 | 95 | # set the APL version from git 96 | 97 | exists ($$PWD/.git) { 98 | GIT_DESCRIBE = $$system(git --git-dir $$PWD/.git --work-tree $$PWD describe --always --tags) 99 | GIT_BRANCH = $$system(git --git-dir $$PWD/.git --work-tree $$PWD rev-parse --abbrev-ref HEAD) 100 | GIT_HASH = $$system(git --git-dir $$PWD/.git --work-tree $$PWD rev-parse --short HEAD) 101 | GIT_TIME = $$system(git --git-dir $$PWD/.git --work-tree $$PWD show --oneline --format=\"%ci\" -s HEAD) 102 | 103 | # determine if we're on a tag matching vX.Y.Z (stable release) 104 | contains(GIT_DESCRIBE, v[0-9]+.[0-9]+.[0-9]+) { 105 | # release version "vX.Y.Z" 106 | GIT_VERSION = $${GIT_DESCRIBE} 107 | } else { 108 | # development version "Development branch:sha date" 109 | GIT_VERSION = "Development $${GIT_BRANCH}:$${GIT_HASH} $${GIT_TIME}" 110 | } 111 | 112 | VERSION = $$replace(GIT_DESCRIBE, "v", "") 113 | VERSION = $$replace(VERSION, "-", ".") 114 | VERSION = $$section(VERSION, ".", 0, 3) 115 | MacBuild { 116 | MAC_VERSION = $$section(VERSION, ".", 0, 2) 117 | MAC_BUILD = $$section(VERSION, ".", 3, 3) 118 | message(ArduPilotLog version $${MAC_VERSION} build $${MAC_BUILD} describe $${GIT_VERSION}) 119 | } else { 120 | message(ArduPilotLog $${GIT_VERSION}) 121 | } 122 | } else { 123 | GIT_VERSION = None 124 | VERSION = 0.0.0 # Marker to indicate out-of-tree build 125 | MAC_VERSION = 0.0.0 126 | MAC_BUILD = 0 127 | } 128 | 129 | DEFINES += GIT_VERSION=\"\\\"$$GIT_VERSION\\\"\" 130 | DEFINES += EIGEN_MPL2_ONLY 131 | 132 | # Installer configuration 133 | 134 | installer { 135 | CONFIG -= debug 136 | CONFIG -= debug_and_release 137 | CONFIG += release 138 | message(Build Installer) 139 | } 140 | 141 | # Setup our supported build flavors 142 | 143 | CONFIG(debug, debug|release) { 144 | message(Debug flavor) 145 | CONFIG += DebugBuild 146 | } else:CONFIG(release, debug|release) { 147 | message(Release flavor) 148 | CONFIG += ReleaseBuild 149 | } else { 150 | error(Unsupported build flavor) 151 | } 152 | 153 | # Setup our build directories 154 | 155 | BASEDIR = $$IN_PWD 156 | 157 | !iOSBuild { 158 | OBJECTS_DIR = $${OUT_PWD}/obj 159 | MOC_DIR = $${OUT_PWD}/moc 160 | UI_DIR = $${OUT_PWD}/ui 161 | RCC_DIR = $${OUT_PWD}/rcc 162 | } 163 | 164 | LANGUAGE = C++ 165 | 166 | LOCATION_PLUGIN_DESTDIR = $${OUT_PWD}/src/QtLocationPlugin 167 | LOCATION_PLUGIN_NAME = QGeoServiceProviderFactoryAPL 168 | 169 | # Turn off serial port warnings 170 | DEFINES += _TTY_NOWARN_ 171 | 172 | MacBuild | LinuxBuild { 173 | QMAKE_CXXFLAGS_WARN_ON += -Wall 174 | WarningsAsErrorsOn { 175 | QMAKE_CXXFLAGS_WARN_ON += -Werror 176 | } 177 | MacBuild { 178 | # Latest clang version has a buggy check for this which cause Qt headers to throw warnings on qmap.h 179 | QMAKE_CXXFLAGS_WARN_ON += -Wno-return-stack-address 180 | # Xcode 8.3 has issues on how MAVLink accesses (packed) message structure members. 181 | # Note that this will fail when Xcode version reaches 10.x.x 182 | XCODE_VERSION = $$system($$PWD/tools/get_xcode_version.sh) 183 | greaterThan(XCODE_VERSION, 8.2.0): QMAKE_CXXFLAGS_WARN_ON += -Wno-address-of-packed-member 184 | } 185 | } 186 | 187 | WindowsBuild { 188 | win32-msvc2015 { 189 | QMAKE_CFLAGS -= -Zc:strictStrings 190 | QMAKE_CXXFLAGS -= -Zc:strictStrings 191 | } 192 | QMAKE_CFLAGS_RELEASE -= -Zc:strictStrings 193 | QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO -= -Zc:strictStrings 194 | 195 | QMAKE_CXXFLAGS_RELEASE -= -Zc:strictStrings 196 | QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO -= -Zc:strictStrings 197 | QMAKE_CXXFLAGS_WARN_ON += /W3 \ 198 | /wd4996 \ # silence warnings about deprecated strcpy and whatnot 199 | /wd4005 \ # silence warnings about macro redefinition 200 | /wd4290 # ignore exception specifications 201 | 202 | WarningsAsErrorsOn { 203 | QMAKE_CXXFLAGS_WARN_ON += /WX 204 | } 205 | } 206 | 207 | # 208 | # Build-specific settings 209 | # 210 | 211 | ReleaseBuild { 212 | DEFINES += QT_NO_DEBUG QT_MESSAGELOGCONTEXT 213 | CONFIG += force_debug_info # Enable debugging symbols on release builds 214 | !iOSBuild { 215 | CONFIG += ltcg # Turn on link time code generation 216 | } 217 | 218 | WindowsBuild { 219 | # Enable function level linking and enhanced optimized debugging 220 | QMAKE_CFLAGS_RELEASE += /Gy /Zo 221 | QMAKE_CXXFLAGS_RELEASE += /Gy /Zo 222 | QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += /Gy /Zo 223 | QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += /Gy /Zo 224 | 225 | # Eliminate duplicate COMDATs 226 | QMAKE_LFLAGS_RELEASE += /OPT:ICF 227 | QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO += /OPT:ICF 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /APLDockWidget.cpp: -------------------------------------------------------------------------------- 1 | #include "APLDockWidget.h" 2 | 3 | #include 4 | #include 5 | 6 | const char* APLDockWidget::_settingsGroup = "DockWidgets"; 7 | 8 | APLDockWidget::APLDockWidget(const QString& title, QAction* action, QWidget* parent) 9 | : QWidget(parent) 10 | , _title(title) 11 | , _action(action) 12 | { 13 | if (action) { 14 | setWindowTitle(title); 15 | setWindowFlags(Qt::Tool); 16 | loadSettings(); 17 | } 18 | } 19 | 20 | // Instead of destroying the widget just hide it 21 | void APLDockWidget::closeEvent(QCloseEvent* event) 22 | { 23 | if (_action) { 24 | saveSettings(); 25 | event->ignore(); 26 | _action->trigger(); 27 | } else { 28 | QWidget::closeEvent(event); 29 | } 30 | } 31 | 32 | void APLDockWidget::loadSettings(void) 33 | { 34 | // TODO: This is crashing for some reason. Disabled until sorted out. 35 | if (0 /*_action*/) { 36 | QSettings settings; 37 | settings.beginGroup(_settingsGroup); 38 | if (settings.contains(_title)) { 39 | restoreGeometry(settings.value(_title).toByteArray()); 40 | } 41 | settings.endGroup(); 42 | } 43 | } 44 | 45 | void APLDockWidget::saveSettings(void) 46 | { 47 | // TODO: This is crashing for some reason. Disabled until sorted out. 48 | if (0 /*_action*/) { 49 | QSettings settings; 50 | settings.beginGroup(_settingsGroup); 51 | settings.setValue(_title, saveGeometry()); 52 | settings.endGroup(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /APLDockWidget.h: -------------------------------------------------------------------------------- 1 | #ifndef APLDockWidget_h 2 | #define APLDockWidget_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class APLDockWidget : public QWidget { 9 | Q_OBJECT 10 | 11 | public: 12 | /// Pass in title = QString() and action = NULL when just using as a regular widget 13 | APLDockWidget(const QString& title, QAction* action, QWidget *parent = 0); 14 | 15 | void loadSettings(void); 16 | void saveSettings(void); 17 | 18 | void closeEvent(QCloseEvent* event); 19 | 20 | protected: 21 | QString _title; 22 | QPointer _action; 23 | static const char* _settingsGroup; 24 | }; 25 | 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /APLLoggingCategory.cpp: -------------------------------------------------------------------------------- 1 | #include "APLLoggingCategory.h" 2 | 3 | #include 4 | 5 | APLLoggingCategoryRegister* _instance = NULL; 6 | const char* APLLoggingCategoryRegister::_filterRulesSettingsGroup = "LoggingFilters"; 7 | 8 | APLLoggingCategoryRegister* APLLoggingCategoryRegister::instance(void) 9 | { 10 | if (!_instance) { 11 | _instance = new APLLoggingCategoryRegister(); 12 | Q_CHECK_PTR(_instance); 13 | } 14 | 15 | return _instance; 16 | } 17 | 18 | QStringList APLLoggingCategoryRegister::registeredCategories(void) 19 | { 20 | _registeredCategories.sort(); 21 | return _registeredCategories; 22 | } 23 | 24 | void APLLoggingCategoryRegister::setCategoryLoggingOn(const QString& category, bool enable) 25 | { 26 | QSettings settings; 27 | 28 | settings.beginGroup(_filterRulesSettingsGroup); 29 | settings.setValue(category, enable); 30 | } 31 | 32 | bool APLLoggingCategoryRegister::categoryLoggingOn(const QString& category) 33 | { 34 | QSettings settings; 35 | 36 | settings.beginGroup(_filterRulesSettingsGroup); 37 | return settings.value(category, false).toBool(); 38 | } 39 | 40 | void APLLoggingCategoryRegister::setFilterRulesFromSettings(const QString& commandLineLoggingOptions) 41 | { 42 | if (!commandLineLoggingOptions.isEmpty()) { 43 | _commandLineLoggingOptions = commandLineLoggingOptions; 44 | } 45 | QString filterRules; 46 | 47 | // Turn off bogus ssl warning 48 | filterRules += "qt.network.ssl.warning=false\n"; 49 | filterRules += "*Log.debug=false\n"; 50 | 51 | // Set up filters defined in settings 52 | foreach (QString category, _registeredCategories) { 53 | if (categoryLoggingOn(category)) { 54 | filterRules += category; 55 | filterRules += ".debug=true\n"; 56 | } 57 | } 58 | 59 | // Command line rules take precedence, so they go last in the list 60 | if (!_commandLineLoggingOptions.isEmpty()) { 61 | QStringList logList = _commandLineLoggingOptions.split(","); 62 | 63 | if (logList[0] == "full") { 64 | filterRules += "*Log.debug=true\n"; 65 | for(int i=1; i 5 | #include 6 | 7 | /// @def APL_LOGGING_CATEGORY 8 | /// This is a APL specific replacement for Q_LOGGING_CATEGORY. It will register the category name into a 9 | /// global list. It's usage is the same as Q_LOGGING_CATEOGRY. 10 | #define APL_LOGGING_CATEGORY(name, ...) \ 11 | static APLLoggingCategory aplCategory ## name (__VA_ARGS__); \ 12 | Q_LOGGING_CATEGORY(name, __VA_ARGS__) 13 | 14 | class APLLoggingCategoryRegister : public QObject 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | static APLLoggingCategoryRegister* instance(void); 20 | 21 | /// Registers the specified logging category to the system. 22 | void registerCategory(const char* category) { _registeredCategories << category; } 23 | 24 | /// Returns the list of available logging category names. 25 | Q_INVOKABLE QStringList registeredCategories(void); 26 | 27 | /// Turns on/off logging for the specified category. State is saved in app settings. 28 | Q_INVOKABLE void setCategoryLoggingOn(const QString& category, bool enable); 29 | 30 | /// Returns true if logging is turned on for the specified category. 31 | Q_INVOKABLE bool categoryLoggingOn(const QString& category); 32 | 33 | /// Sets the logging filters rules from saved settings. 34 | /// @param commandLineLogggingOptions Logging options which were specified on the command line 35 | void setFilterRulesFromSettings(const QString& commandLineLoggingOptions); 36 | 37 | private: 38 | APLLoggingCategoryRegister(void) { } 39 | 40 | QStringList _registeredCategories; 41 | QString _commandLineLoggingOptions; 42 | 43 | static const char* _filterRulesSettingsGroup; 44 | }; 45 | 46 | class APLLoggingCategory 47 | { 48 | public: 49 | APLLoggingCategory(const char* category) { APLLoggingCategoryRegister::instance()->registerCategory(category); } 50 | }; 51 | 52 | #endif // APLLOGGINGCATEGORY_H 53 | -------------------------------------------------------------------------------- /APLSetup.pri: -------------------------------------------------------------------------------- 1 | QMAKE_POST_LINK += echo "Copying files" 2 | 3 | # 4 | # Copy the application resources to the associated place alongside the application 5 | # 6 | 7 | LinuxBuild { 8 | DESTDIR_COPY_RESOURCE_LIST = $$DESTDIR 9 | } 10 | 11 | MacBuild { 12 | DESTDIR_COPY_RESOURCE_LIST = $$DESTDIR/$${TARGET}.app/Contents/MacOS 13 | } 14 | 15 | # Windows version of QMAKE_COPY_DIR of course doesn't work the same as Mac/Linux. It will only 16 | # copy the contents of the source directory. It doesn't create the top level source directory 17 | # in the target. 18 | WindowsBuild { 19 | # Make sure to keep both side of this if using the same set of directories 20 | DESTDIR_COPY_RESOURCE_LIST = $$replace(DESTDIR,"/","\\") 21 | BASEDIR_COPY_RESOURCE_LIST = $$replace(BASEDIR,"/","\\") 22 | # QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY_DIR \"$$BASEDIR_COPY_RESOURCE_LIST\\resources\\flightgear\" \"$$DESTDIR_COPY_RESOURCE_LIST\\flightgear\" 23 | } else { 24 | !MobileBuild { 25 | # Make sure to keep both sides of this if using the same set of directories 26 | # QMAKE_POST_LINK += && $$QMAKE_COPY_DIR $$BASEDIR/resources/flightgear $$DESTDIR_COPY_RESOURCE_LIST 27 | } 28 | } 29 | 30 | # 31 | # Perform platform specific setup 32 | # 33 | 34 | iOSBuild | MacBuild { 35 | # Update version info in bundle 36 | QMAKE_POST_LINK += && /usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString $${MAC_VERSION}\" $$DESTDIR/$${TARGET}.app/Contents/Info.plist 37 | QMAKE_POST_LINK += && /usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $${MAC_BUILD}\" $$DESTDIR/$${TARGET}.app/Contents/Info.plist 38 | } 39 | 40 | MacBuild { 41 | # Copy non-standard frameworks into app package 42 | QMAKE_POST_LINK += && rsync -a --delete $$BASEDIR/libs/lib/Frameworks $$DESTDIR/$${TARGET}.app/Contents/ 43 | } 44 | 45 | WindowsBuild { 46 | BASEDIR_WIN = $$replace(BASEDIR, "/", "\\") 47 | DESTDIR_WIN = $$replace(DESTDIR, "/", "\\") 48 | QT_BIN_DIR = $$dirname(QMAKE_QMAKE) 49 | 50 | # Copy dependencies 51 | DebugBuild: DLL_QT_DEBUGCHAR = "d" 52 | ReleaseBuild: DLL_QT_DEBUGCHAR = "" 53 | 54 | for(COPY_FILE, COPY_FILE_LIST) { 55 | QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"$$COPY_FILE\" \"$$DESTDIR_WIN\" 56 | } 57 | 58 | ReleaseBuild { 59 | # Copy Visual Studio DLLs 60 | # Note that this is only done for release because the debugging versions of these DLLs cannot be redistributed. 61 | win32-msvc2010 { 62 | QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"C:\\Windows\\System32\\msvcp100.dll\" \"$$DESTDIR_WIN\" 63 | QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"C:\\Windows\\System32\\msvcr100.dll\" \"$$DESTDIR_WIN\" 64 | 65 | } else:win32-msvc2012 { 66 | QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"C:\\Windows\\System32\\msvcp110.dll\" \"$$DESTDIR_WIN\" 67 | QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"C:\\Windows\\System32\\msvcr110.dll\" \"$$DESTDIR_WIN\" 68 | 69 | } else:win32-msvc2013 { 70 | QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"C:\\Windows\\System32\\msvcp120.dll\" \"$$DESTDIR_WIN\" 71 | QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"C:\\Windows\\System32\\msvcr120.dll\" \"$$DESTDIR_WIN\" 72 | 73 | } else:win32-msvc2015 { 74 | QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"C:\\Windows\\System32\\msvcp140.dll\" \"$$DESTDIR_WIN\" 75 | QMAKE_POST_LINK += $$escape_expand(\\n) $$QMAKE_COPY \"C:\\Windows\\System32\\vcruntime140.dll\" \"$$DESTDIR_WIN\" 76 | 77 | } else { 78 | error("Visual studio version not supported, installation cannot be completed.") 79 | } 80 | } 81 | 82 | DEPLOY_TARGET = $$shell_quote($$shell_path($$DESTDIR_WIN\\$${TARGET}.exe)) 83 | QMAKE_POST_LINK += $$escape_expand(\\n) $$QT_BIN_DIR\\windeployqt --no-compiler-runtime --qmldir=$${BASEDIR_WIN}\\src $${DEPLOY_TARGET} 84 | } 85 | 86 | LinuxBuild { 87 | QMAKE_POST_LINK += && mkdir -p $$DESTDIR/Qt/libs && mkdir -p $$DESTDIR/Qt/plugins 88 | 89 | # QT_INSTALL_LIBS 90 | QT_LIB_LIST = \ 91 | libQt5Core.so.5 \ 92 | libQt5DBus.so.5 \ 93 | libQt5Gui.so.5 \ 94 | libQt5Location.so.5 \ 95 | libQt5Multimedia.so.5 \ 96 | libQt5MultimediaQuick_p.so.5 \ 97 | libQt5Network.so.5 \ 98 | libQt5OpenGL.so.5 \ 99 | libQt5Positioning.so.5 \ 100 | libQt5PrintSupport.so.5 \ 101 | libQt5Qml.so.5 \ 102 | libQt5Quick.so.5 \ 103 | libQt5QuickControls2.so.5 \ 104 | libQt5QuickTemplates2.so.5 \ 105 | libQt5QuickWidgets.so.5 \ 106 | libQt5SerialPort.so.5 \ 107 | libQt5Sql.so.5 \ 108 | libQt5Svg.so.5 \ 109 | libQt5Test.so.5 \ 110 | libQt5Widgets.so.5 \ 111 | libQt5XcbQpa.so.5 \ 112 | libQt5Xml.so.5 \ 113 | libQt5TextToSpeech.so.5 114 | 115 | !contains(DEFINES, __rasp_pi2__) { 116 | QT_LIB_LIST += \ 117 | libicudata.so.56 \ 118 | libicui18n.so.56 \ 119 | libicuuc.so.56 120 | } 121 | 122 | for(QT_LIB, QT_LIB_LIST) { 123 | QMAKE_POST_LINK += && $$QMAKE_COPY --dereference $$[QT_INSTALL_LIBS]/$$QT_LIB $$DESTDIR/Qt/libs/ 124 | } 125 | 126 | # QT_INSTALL_PLUGINS 127 | QT_PLUGIN_LIST = \ 128 | bearer \ 129 | geoservices \ 130 | iconengines \ 131 | imageformats \ 132 | platforminputcontexts \ 133 | platforms \ 134 | position \ 135 | sqldrivers 136 | 137 | !contains(DEFINES, __rasp_pi2__) { 138 | QT_PLUGIN_LIST += xcbglintegrations 139 | } 140 | 141 | for(QT_PLUGIN, QT_PLUGIN_LIST) { 142 | QMAKE_POST_LINK += && $$QMAKE_COPY --dereference --recursive $$[QT_INSTALL_PLUGINS]/$$QT_PLUGIN $$DESTDIR/Qt/plugins/ 143 | } 144 | 145 | # QT_INSTALL_QML 146 | QMAKE_POST_LINK += && $$QMAKE_COPY --dereference --recursive $$[QT_INSTALL_QML] $$DESTDIR/Qt/ 147 | 148 | # ArduPilotLog start script 149 | QMAKE_POST_LINK += && $$QMAKE_COPY $$BASEDIR/deploy/ardupilotlog-start.sh $$DESTDIR 150 | QMAKE_POST_LINK += && $$QMAKE_COPY $$BASEDIR/deploy/ardupilotlog.desktop $$DESTDIR 151 | QMAKE_POST_LINK += && $$QMAKE_COPY $$BASEDIR/resources/icons/ardupilotlog.png $$DESTDIR 152 | } 153 | -------------------------------------------------------------------------------- /ArduPilotLog.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2017-12-23T11:01:59 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui sql qml quick quickwidgets 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport 10 | 11 | include(APLCommon.pri) 12 | 13 | TARGET = ArduPilotLog 14 | TEMPLATE = app 15 | 16 | DebugBuild { 17 | DESTDIR = $${OUT_PWD}/debug 18 | } else { 19 | DESTDIR = $${OUT_PWD}/release 20 | } 21 | 22 | LinuxBuild { 23 | CONFIG += qesp_linux_udev 24 | } 25 | 26 | WindowsBuild { 27 | RC_ICONS = resources/icons/ardupilotlog.ico 28 | } 29 | 30 | # The following define makes your compiler emit warnings if you use 31 | # any feature of Qt which has been marked as deprecated (the exact warnings 32 | # depend on your compiler). Please consult the documentation of the 33 | # deprecated API in order to know how to port your code away from it. 34 | DEFINES += QT_DEPRECATED_WARNINGS 35 | 36 | # You can also make your code fail to compile if you use deprecated APIs. 37 | # In order to do so, uncomment the following line. 38 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 39 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 40 | 41 | 42 | SOURCES += \ 43 | main.cpp \ 44 | mainwindow.cpp \ 45 | APLLoggingCategory.cpp \ 46 | APLDockWidget.cpp \ 47 | src/Dialog.cpp \ 48 | src/DialogLoad.cpp \ 49 | src/APLRead.cpp \ 50 | src/APLReadConf.cpp \ 51 | src/APLDB.cpp \ 52 | qcustomplot.cpp \ 53 | src/DataAnalyzeController.cpp \ 54 | src/APLQmlWidgetHolder.cpp \ 55 | 56 | HEADERS += \ 57 | mainwindow.h \ 58 | APLLoggingCategory.h \ 59 | APLDockWidget.h \ 60 | src/Dialog.h \ 61 | src/DialogLoad.h \ 62 | src/APLRead.h \ 63 | src/APLReadConf.h \ 64 | src/LogStructure.h \ 65 | src/APLDB.h \ 66 | qcustomplot.h \ 67 | src/DataAnalyzeController.h \ 68 | src/DataAnalyze.h \ 69 | src/APLQmlWidgetHolder.h \ 70 | 71 | FORMS += \ 72 | mainwindow.ui \ 73 | src/APLQmlWidgetHolder.ui 74 | 75 | include(APLSetup.pri) 76 | 77 | DISTFILES += \ 78 | APLCommon.pri 79 | 80 | RESOURCES += \ 81 | $$PWD/aplresources.qrc \ 82 | $$PWD/ardupilotlog.qrc 83 | -------------------------------------------------------------------------------- /ArduPilotLog.udb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/ArduPilotLog.udb -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # ArduPilotLog 开源说明 2 | 概要 3 | --- 4 | ArduPilotLog 是 ardupilot 日志数据绘图软件。为快速展示 Log 日志数据,以便通过分析数据排查程序 bug 或累积经验而设计。 5 | 6 | 打开"_\*.bin_"类型日志 7 | --- 8 | 打开方法如下图所示: 9 |
![ArduPilotLog_1_OpenLog.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_1_OpenLog.png)
10 |
![ArduPilotLog_2_OpenLog.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_2_OpenLog.png)
11 | 12 | 三种绘图方法 13 | --- 14 | 1. 点选绘图 15 | > “点选绘图”在不明确看哪一种日志数据时使用。 16 | > 比如:对于飞机的某种奇怪表现,往往不能立刻明确是哪里出了问题,这时怀疑对象泛围大,用点选方式为猜测快速提供依据。 17 | 18 | ![ArduPilotLog_3_ClickPlot.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_3_ClickPlot.png) 19 | 20 | 2. 数据分析窗(点选绘图Plus) 21 | > “数据分析窗”在小泛围锁定目标数据时使用。 22 | > 比如:通过点选绘图已初步锁定某种现象与某几类数据表现相关`(注:少于10类)`,此时须要精确绘图。 23 | 24 |
打开“数据分析窗”
25 |
![ArduPilotLog_4_DataAnalyze.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_4_DataAnalyze.png)
26 |
“数据分析窗”说明
27 |
![ArduPilotLog_5_DataAnalyze.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_5_DataAnalyze.png)
28 |
通过“数据分析窗”绘图
29 |
![ArduPilotLog_6_DataAnalyze.jpg](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_6_DataAnalyze.jpg)
30 | 31 | 3. 脚本绘图 32 | > “脚本绘图”用于反复验证已锁定的目标数据是否合理的情形。 33 | > 将与当前问题有关的数据锁定后,往往需要多次采集 Log 日志,重复分析以便证实。这时使用脚本绘图比较方便,以免去每次点选、调整比例等麻烦。 34 | 35 |
加载脚本
36 |
![ArduPilotLog_7_ScriptPlot.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_7_ScriptPlot.png)
37 |
![ArduPilotLog_8_ScriptPlot.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_8_ScriptPlot.png)
38 | 39 |
脚本语法如下图(也可见 **[conf/ReadMe.md](https://github.com/SuWeipeng/ArduPilotLog/blob/master/conf/ReadMe.md)**)
40 | ![ArduPilotLog_9_ScriptPlot.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_9_ScriptPlot.png) 41 | 42 | ## 编译方法 43 | ArduPilotLog 软件架构源于[qgroundcontrol](https://github.com/mavlink/qgroundcontrol),因此[编译方法](https://dev.qgroundcontrol.com/en/getting_started/)与QGC相同。 44 | 45 | ## 软件的由来 46 |
起初只是为了学习QGC,QGC功能多、代码构架复杂不是一下就能看懂的。
47 |
后来在研究ardupilot的过程中经常要分析Log。使用过MissionPlanner、APM Planner等软件看Log日志,有几个体验一直觉得不爽:
48 | 1. MissionPlanner最难受的是有时看看日志会卡死。 49 | 2. 我更关心图线,不是很在意数据,而界面留了一部分展示数据,每次都要手动拉小数据部分。 50 | 3. “看Log日志数据”只是这些软件的“一部分”功能。也就是说每次为了看数据,必须先要打开这些软件,等待其余功能加载完毕,然后点到这个功能,浪费时间。 51 | 4. 于上位机的角度讲,QGC的界面划分和操作方式更适合我,却单单缺少查看Log日志数据这个功能。 52 | 53 |
基于以上原因,就自己写个软件搞定自己的需求吧。
54 | 55 | ## 作者本人对此软件的评价 56 | 1. 这不是一个完美的软件。 57 | 2. 这个软件最初是以学习为目的而写的,没有走太完整的功能设计过程,业余时间想到哪写到哪。若要完美整合已实现的功能,就要重构了。 58 | 3. 代码适合想学QGC的朋友们看(看git的开发流程log,都是0起点开始的)。 59 | 4. 软件适合正在学习或调试ardupilot的朋友们使用。 60 | 由其是 **“脚本绘图”** 功能,**其目的就是给无形的经验累积提供一个容身之所**,让经验有形,便于自我反复推敲和与人交流。 61 | 5. 代码开发过程中经历了:QGC架构分析、用户体验设计、功能模块拆分与整合等过程,麻雀小可能还有点丑,但五脏全。 62 | 63 | ## 软件涉及到的知识点 64 | > 跟我一样0起点想学QGC的朋友可能关心这些,在此简单例举。 65 | 1. QGC架构。 66 | 2. QT ui界面开发。 67 | 3. QT QML界面开发。 68 | 4. QT ui 与 QML 整合方法。 69 | 5. QT SQLite 数据库。 70 | 6. QT 界面与后台数据的分离与整合。 71 | 7. QT 信号与槽通信机制。 72 | 8. QT 二进制文件读写。 73 | 9. QT 文本文件读取。 74 | 10. QT 正则表达式使用。 75 | 11. ardupilot 日志文件结构。 76 | 12. qcustomplot 绘图插件。 77 | 13. QGC qCDebug()分类控制显示调试日志的方法。 78 | 79 | ## 对于更进一步的数据分析 80 | 本软件以快速显示图线为目的,对于三种绘图方式仍不能满足的数据分析需求,则须将数据导入MATLAB(诸如:给数据进行低通滤波、数据作为控制仿真的输入等需求。) 81 |
[将数据导入MATLAB的脚本点此链接](https://github.com/SuWeipeng/ArduPilotLog/tree/master/matlab)
82 | 83 | ## arduplilot日志数据的交换 84 |
本软件设计的目的之一是:让不同平台能方便的使用Log日志数据。因此引入了SQLite数据库。
85 |
数据的存在形式:ardupilot存入SD卡中的 \*.bin 二进制格式,转到 SQLite 数据库的 \*.db 格式。
86 |
![ArduPilotLog_10_SQLite.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_10_SQLite.png)
87 | * MATLAB、Excel等可通过\*.db文件获取日志内容。 88 | * 对数据感兴趣的时候,可通过 SQLite Expert 之类软件直接展示数据内容。 89 | 90 | ## 后续的更新 91 | 本软件后续会把作者已知未实现的功能写个 feature list,已知 bug 写个 bug list。对于 feature 和 bug 的划分是软件开发纠分不清的问题,在此作者表示:后续这些只是个 list 而已,很可能不会再加入新 feature 或解决小 bug(致命 bug 除外)。 92 | 93 | **后续更新会往以下几个方向发展:** 94 | 1. 分享一些开发过程中的心得。 95 | 2. 对某个知识点的剖析。 96 | 3. 加入新的 *.conf 绘图脚本(分享ardupilot“有形的”经验) 97 | 4. 软件开发经验分享: 98 | 1)说说软件架构是什么,为什么重要。 99 | 2)说说本软件开发的功能设计、功能模块划分与整合是怎样体现的。 100 | 3)说说本软件为提升用户体验感而做了哪些改进。 101 | 4)说说当有上位机开发需求的时候,应该怎样入手。 102 | 5)其他各种想到的值得分享的东西。 103 | 104 | **这是一个因学习而生的项目,它未来更大的意义不是从丑小鸭进化成白天鹅,而是为同样0起点的后来人铺上一块前往更高层次的砖。** 105 | 106 | ## 喜欢交流的朋友可以加作者微信 107 |
![weixin.png](https://github.com/SuWeipeng/img/raw/master/weixinhaoyou.png)
108 | -------------------------------------------------------------------------------- /aplresources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | resources/icons/ardupilotlog.ico 4 | 5 | 6 | -------------------------------------------------------------------------------- /ardupilotlog.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | src/AutoResize.qml 4 | src/DataAnalyze.qml 5 | 6 | 7 | -------------------------------------------------------------------------------- /chibios log.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/chibios log.bin -------------------------------------------------------------------------------- /conf/001_ATT_Roll_Ang.conf: -------------------------------------------------------------------------------- 1 | ATT.DesRoll.0.0 2 | ATT.Roll.0.2 3 | -------------------------------------------------------------------------------- /conf/002_ATT_Roll_AngVel.conf: -------------------------------------------------------------------------------- 1 | PIDR.Tar.0.0 2 | PIDR.Act.0.1 3 | -------------------------------------------------------------------------------- /conf/003_ATT_Roll_FeedFoward.conf: -------------------------------------------------------------------------------- 1 | FFWD.TarX.0.0 2 | FFWD.DesX.0.2 3 | -------------------------------------------------------------------------------- /conf/004_ATT_Roll_LowpassD.conf: -------------------------------------------------------------------------------- 1 | PIDR.D.0.0 2 | PIDR.DR.0.1 3 | -------------------------------------------------------------------------------- /conf/005_ATT_Roll_PID.conf: -------------------------------------------------------------------------------- 1 | PIDR.P.0.0 2 | PIDR.I.0.1 3 | PIDR.D.0.2 4 | PIDR.FF.0.8 5 | -------------------------------------------------------------------------------- /conf/006_ATT_Pitch_Ang.conf: -------------------------------------------------------------------------------- 1 | ATT.DesPitch.0.0 2 | ATT.Pitch.0.2 3 | -------------------------------------------------------------------------------- /conf/007_ATT_Pitch_AngVel.conf: -------------------------------------------------------------------------------- 1 | PIDP.Tar.0.0 2 | PIDP.Act.0.1 3 | -------------------------------------------------------------------------------- /conf/008_ATT_Pitch_FeedFoward.conf: -------------------------------------------------------------------------------- 1 | FFWD.TarY.0.0 2 | FFWD.DesY.0.2 3 | -------------------------------------------------------------------------------- /conf/009_ATT_Pitch_LowpassD.conf: -------------------------------------------------------------------------------- 1 | PIDP.D.0.0 2 | PIDP.DR.0.1 3 | -------------------------------------------------------------------------------- /conf/010_ATT_Pitch_PID.conf: -------------------------------------------------------------------------------- 1 | PIDP.P.0.0 2 | PIDP.I.0.1 3 | PIDP.D.0.2 4 | PIDP.FF.0.8 5 | -------------------------------------------------------------------------------- /conf/011_ATT_Yaw_Ang.conf: -------------------------------------------------------------------------------- 1 | ATT.DesYaw.0.0 2 | ATT.Yaw.0.2 3 | -------------------------------------------------------------------------------- /conf/012_ATT_Yaw_AngVel.conf: -------------------------------------------------------------------------------- 1 | PIDY.Tar.0.0 2 | PIDY.Act.0.1 3 | -------------------------------------------------------------------------------- /conf/013_ATT_Yaw_FeedFoward.conf: -------------------------------------------------------------------------------- 1 | FFWD.TarZ.0.0 2 | FFWD.DesZ.0.2 3 | -------------------------------------------------------------------------------- /conf/014_ATT_Yaw_LowpassD.conf: -------------------------------------------------------------------------------- 1 | PIDY.D.0.0 2 | PIDY.DR.0.1 3 | -------------------------------------------------------------------------------- /conf/015_ATT_Yaw_PID.conf: -------------------------------------------------------------------------------- 1 | PIDY.P.0.0 2 | PIDY.I.0.1 3 | PIDY.D.0.2 4 | PIDY.FF.0.8 5 | -------------------------------------------------------------------------------- /conf/016_ATT_Yaw_LowpassIn.conf: -------------------------------------------------------------------------------- 1 | PIDY.LPE.0.0 2 | PIDY.E.0.1 3 | -------------------------------------------------------------------------------- /conf/017_TILT_Ang_ErrZ.conf: -------------------------------------------------------------------------------- 1 | # deg2rad(120)/4.5 = 0.46542113 2 | 3 | TILT.ErrAng.0.0 4 | TILT.ErrZ.0.2 5 | <> TILT:0.46542113 0.1 6 | ATT.DesYaw.0.5(0.002,0,0) 7 | ATT.Yaw.0.8(0.002,0,0) -------------------------------------------------------------------------------- /conf/018_Yaw_out_off_control.conf: -------------------------------------------------------------------------------- 1 | # pi()/180 = 0.01745329252 2 | # pi()*(120/4.5)/180 = 0.465421133865 3 | 4 | ATT.DesYaw.0.0(0.01745329252, 0, 0) 5 | ATT.Yaw.0.1(0.01745329252, 0, 0) 6 | TILT.ErrAng.0.2(1, 0, 0) 7 | TILT.ErrZ.4.3(1, 0, 0) 8 | PIDY.E.0.4(1, 0, 0) 9 | PIDY.LPE.7.5(1, 0, 0) 10 | <> PIDY:0.465421133865 0.6 11 | <> PIDY:0.10471975512 0.7 12 | -------------------------------------------------------------------------------- /conf/019_RC_Failsafe.conf: -------------------------------------------------------------------------------- 1 | # BATT_LOW_VOLT 3.3v 2 | 3 | MODE.ModeNum.7.0(100, 0, 0) 4 | RCIN.C3.0.1(1, 0, 0) 5 | BAT.VoltR.0.2(1000, 0, 0) 6 | <> BAT:3300 0.3 7 | -------------------------------------------------------------------------------- /conf/020_VD_Z_RC.conf: -------------------------------------------------------------------------------- 1 | RCIN.C3.7.1(0.5, 0, -750) 2 | ALT.VD.7.0(1, 0, 0) 3 | 4 | -------------------------------------------------------------------------------- /conf/021_PSC_POS_Z.conf: -------------------------------------------------------------------------------- 1 | ALT.PT.0.0(1, 0, 0) 2 | ALT.PR.0.2(1, 0, 0) 3 | 4 | -------------------------------------------------------------------------------- /conf/022_PSC_VEL_Z.conf: -------------------------------------------------------------------------------- 1 | ALT.VT.0.0(1, 0, 0) 2 | ALT.VR.0.2(1, 0, 0) -------------------------------------------------------------------------------- /conf/023_PSC_ACC_Z.conf: -------------------------------------------------------------------------------- 1 | PIDA.Des.7.0(1, 0, 0) 2 | PIDA.Act.7.2(1, 0, 0) 3 | PIDA.P.0.1(1, 0, 0) 4 | PIDA.I.0.3(1, 0, 0) 5 | PIDA.D.0.4(1, 0, 0) -------------------------------------------------------------------------------- /conf/024_BARO_IMU.conf: -------------------------------------------------------------------------------- 1 | BARO.Press.0.0(1, 0, 0) 2 | IMU.AccX.0.1(0.2, 0, 101070) 3 | -------------------------------------------------------------------------------- /conf/025_PIDA_D_Lowpass.conf: -------------------------------------------------------------------------------- 1 | PIDA.DR.0.2(1, 0, 0) 2 | PIDA.D.0.0(1, 0, 0) -------------------------------------------------------------------------------- /conf/026_PIDA_E_Lowpass.conf: -------------------------------------------------------------------------------- 1 | PIDA.E.0.2(1, 0, 0) 2 | PIDA.LPE.0.0(1, 0, 0) -------------------------------------------------------------------------------- /conf/027_PSC_VEL_FF.conf: -------------------------------------------------------------------------------- 1 | ALT.VT.0.2(1, 0, 0) 2 | ALT.VD.7.0(1, 0, 0) 3 | ALT.VR.0.1(1, 0, 0) 4 | RCIN.C3.0.3(0.5, 0, -650) -------------------------------------------------------------------------------- /conf/028_FLOW_X.conf: -------------------------------------------------------------------------------- 1 | OF.flowX.0.0(1, 0, 0) 2 | OF.bodyX.0.2(1, 0, 0) 3 | IMU.GyrX.0.1(1, 0, 0) -------------------------------------------------------------------------------- /conf/029_FLOW_Y.conf: -------------------------------------------------------------------------------- 1 | OF.flowY.0.0(1, 0, 0) 2 | OF.bodyY.0.2(1, 0, 0) 3 | IMU.GyrY.0.1(1, 0, 0) -------------------------------------------------------------------------------- /conf/030_RPYT.conf: -------------------------------------------------------------------------------- 1 | RPYT.r.0.0(1, 0, 0) 2 | RPYT.p.0.1(1, 0, 0) 3 | RPYT.y.0.2(1, 0, 0) 4 | RPYT.t.0.3(1, 0, 0) -------------------------------------------------------------------------------- /conf/031_ATT_Roll_LowpassT.conf: -------------------------------------------------------------------------------- 1 | PIDR.Tar.0.0 2 | PIDR.TR.0.1 3 | -------------------------------------------------------------------------------- /conf/032_ATT_Roll_LowpassE.conf: -------------------------------------------------------------------------------- 1 | PIDR.Err.0.0 2 | PIDR.ER.0.1 3 | -------------------------------------------------------------------------------- /conf/ReadMe.md: -------------------------------------------------------------------------------- 1 | # 配置文件的格式 2 | ## 一、绘制LOG数据 3 | > LineStyle: 0-正常,1-加粗,2-加阴影,3-加粗加阴影,4-虚线,5-虚线加粗,6-点虚线,7-线上空心圆,8-线上实心圆,9-只有空心圆 4 | > Color: 0-红,1-绿,2-蓝,3-紫,4-棕,5-粉,6-深天蓝,7-橙,8-深青,9-金 5 | ### 1. 无申缩或相位变换 6 | `Table.Field.LineStyle.Color`,例如:ATT.DesRoll.0.0 7 | ### 2. 有申缩或相位变换 8 | `Table.Field.LineStyle.Color(Scale,OffsetX,OffsetY)`,例如:ATT.DesRoll.0.0(2,0,0) 9 | ## 二、绘制参考线 10 | ` Table:value LineStyle.Color`,例如:<const> BARO:200 0.0 11 | -------------------------------------------------------------------------------- /deploy/ardupilotlog-start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | HERE="$(dirname "$(readlink -f "${0}")")" 3 | export LD_LIBRARY_PATH="${HERE}/usr/lib/x86_64-linux-gnu":"${HERE}/Qt/libs":$LD_LIBRARY_PATH 4 | export QML2_IMPORT_PATH="${HERE}/Qt/qml" 5 | export QT_PLUGIN_PATH="${HERE}/Qt/plugins" 6 | 7 | # hack until icon issue with AppImage is resolved 8 | mkdir -p ~/.icons && cp ${HERE}/ardupilotlog.png ~/.icons 9 | 10 | "${HERE}/ArduPilotLog" "$@" 11 | -------------------------------------------------------------------------------- /deploy/ardupilotlog.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=ArduPilotLog 4 | GenericName=ArduPilot Log 5 | Comment=Read ArduPilot binary log 6 | Icon=ardupilotlog 7 | Exec=ardupilotlog-start.sh 8 | Terminal=false 9 | Categories=Utility; 10 | -------------------------------------------------------------------------------- /doc/compile.md: -------------------------------------------------------------------------------- 1 | ### 编译出错问题及解决办法汇总 2 | #### Error 1117 3 | ##### 提示:“jom: D:\build-ArduPilotLog-Desktop_Qt_5_11_1_MSVC2015_32bit-Release\Makefile.Release [release\ArduPilotLog.exe] Error 1117” 4 | ##### 办法:在 git 流中加标签(Tag),形式为:va.b.c(例:v1.0.0) 5 | -------------------------------------------------------------------------------- /gitlab.yml: -------------------------------------------------------------------------------- 1 | ## Default project features settings 2 | default_projects_features: 3 | issues: true 4 | merge_requests: true 5 | wiki: true 6 | snippets: false 7 | builds: false 8 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | #define QCDEBUG_FILTER_RULES "MainWindowLog,APLDBLog,APLReadLog,DataAnalyzeLog,DialogLog,APLReadConfLog" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | QApplication a(argc, argv); 9 | MainWindow w; 10 | 11 | APLLoggingCategoryRegister::instance()->setFilterRulesFromSettings(QCDEBUG_FILTER_RULES); 12 | w.setWindowTitle("ArduPilotLog"); 13 | w.show(); 14 | 15 | return a.exec(); 16 | } 17 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "mainwindow.h" 5 | #include "ui_mainwindow.h" 6 | #include "src/APLRead.h" 7 | #include "src/APLReadConf.h" 8 | #include "src/APLDB.h" 9 | #include "src/DataAnalyze.h" 10 | #include "src/DataAnalyzeController.h" 11 | 12 | APL_LOGGING_CATEGORY(MAIN_WINDOW_LOG, "MainWindowLog") 13 | 14 | #define ARRAY_SIZE(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0])) 15 | 16 | bool MainWindow::_customPlot_hold_on; 17 | int MainWindow::_comboBoxIndex; 18 | bool MainWindow::_X_axis_changed; 19 | MainWindow* MainWindow::_instance; 20 | 21 | static const char *rgDockWidgetNames[] = { 22 | "DATA Analyze" 23 | }; 24 | 25 | enum DockWidgetTypes { 26 | DATA_ANALYZE 27 | }; 28 | 29 | MainWindow::MainWindow(QWidget *parent) 30 | : QMainWindow(parent) 31 | , _dialog(new Dialog) 32 | , _dialog_load(new DialogLoad) 33 | , _table("") 34 | , _field("") 35 | , _comboBoxListINIT(true) 36 | , _action_bold(0x1<<0) 37 | , _conf_plot(false) 38 | , _is_constant(false) 39 | , _replot(false) 40 | , _plotConf(false) 41 | { 42 | qmlRegisterType("ArduPilotLog.Controllers", 1, 0, "DataAnalyzeController"); 43 | 44 | int screenWidth=QApplication::desktop()->width(); 45 | int screenHeight=QApplication::desktop()->height(); 46 | _ui.setupUi(this); 47 | this->resize(screenWidth/2, screenHeight/2); 48 | _buildCommonWidgets(); 49 | _ui.splitter->setStretchFactor(0, 1); 50 | _ui.splitter->setStretchFactor(1, 8); 51 | initTreeWidget(); 52 | _instance = this; 53 | 54 | for(int i=0; i<10; i++){ 55 | shapes[i] << QCPScatterStyle::ssCircle; 56 | shapes[i] << QCPScatterStyle::ssDisc; 57 | shapes[i] << QCPScatterStyle::ssDiamond; 58 | shapes[i] << QCPScatterStyle::ssCrossCircle; 59 | shapes[i] << QCPScatterStyle::ssPlusCircle; 60 | 61 | colors[i] << QColor(255, 0, 0); // Red 62 | colors[i] << QColor(34, 139, 34); // Green 63 | colors[i] << QColor(0, 0, 255); // Blue 64 | colors[i] << QColor(160, 32, 240); // Purple 65 | colors[i] << QColor(139, 35, 35); // Brown 66 | colors[i] << QColor(255, 20, 147); // Pink 67 | colors[i] << QColor(0, 104, 139); // DeepSkyBlue 68 | colors[i] << QColor(255, 140, 0); // Orange 69 | colors[i] << QColor(0, 139, 139); // DarkCyan 70 | colors[i] << QColor(205, 149, 12); // Gold 71 | } 72 | 73 | connect(_ui.actionOpenArduPilotLog, &QAction::triggered, _ui.treeWidget, &QTreeWidget::clear); 74 | connect(_ui.actionOpenArduPilotLog, &QAction::triggered, this, &MainWindow::clearGraph); 75 | connect(_ui.actionOpenArduPilotLog, &QAction::triggered, _dialog, &Dialog::showFile); 76 | connect(_ui.actionLoad, &QAction::triggered, _dialog_load, &DialogLoad::showFile); 77 | connect(_ui.actionSaveDBFile, &QAction::triggered, _dialog, &Dialog::saveFile); 78 | connect(_dialog->getAPLRead(), &APLRead::fileOpened, this, &MainWindow::_fileOpenedTrigger); 79 | connect(_dialog_load->getAPLReadConf(), &APLReadConf::fileOpened, this, &MainWindow::_confOpenedTrigger); 80 | connect(_dialog, &Dialog::saveSuccess, this, &MainWindow::_saveSuccessMessage); 81 | connect(this, &MainWindow::treeWidgetAddItem, this, &MainWindow::setComboboxList); 82 | } 83 | 84 | MainWindow::~MainWindow() 85 | { 86 | delete _dialog; 87 | } 88 | 89 | void MainWindow::closeEvent(QCloseEvent * event) 90 | { 91 | for (int i = 0, end = ARRAY_SIZE(rgDockWidgetNames); i < end; i++) { 92 | const char* pDockWidgetName = rgDockWidgetNames[i]; 93 | if(_mapName2DockWidget[pDockWidgetName]){ 94 | if(_mapName2DockWidget[pDockWidgetName]->isVisible()){ 95 | _mapName2DockWidget[pDockWidgetName]->closeEvent(event); 96 | } 97 | } 98 | } 99 | QWidget::closeEvent(event); 100 | } 101 | 102 | void MainWindow::_buildCommonWidgets(void) 103 | { 104 | // Populate widget menu 105 | for (int i = 0, end = ARRAY_SIZE(rgDockWidgetNames); i < end; i++) { 106 | 107 | const char* pDockWidgetName = rgDockWidgetNames[i]; 108 | 109 | // Add to menu 110 | QAction* action = new QAction(pDockWidgetName, this); 111 | action->setCheckable(true); 112 | action->setData(i); 113 | connect(action, &QAction::triggered, this, &MainWindow::_showDockWidgetAction); 114 | _ui.menuTools->addAction(action); 115 | _mapName2Action[pDockWidgetName] = action; 116 | } 117 | } 118 | 119 | void MainWindow::_showDockWidgetAction(bool show) 120 | { 121 | QAction* action = qobject_cast(QObject::sender()); 122 | Q_ASSERT(action); 123 | _showDockWidget(rgDockWidgetNames[action->data().toInt()], show); 124 | } 125 | 126 | /// Shows or hides the specified dock widget, creating if necessary 127 | void MainWindow::_showDockWidget(const QString& name, bool show) 128 | { 129 | // Create the inner widget if we need to 130 | if (!_mapName2DockWidget.contains(name)) { 131 | if(!_createInnerDockWidget(name)) { 132 | qWarning() << "Trying to load non existent widget:" << name; 133 | return; 134 | } 135 | }else{ 136 | if(name.compare(rgDockWidgetNames[0]) == 0){ 137 | requestTableList(); 138 | } 139 | } 140 | Q_ASSERT(_mapName2DockWidget.contains(name)); 141 | APLDockWidget* dockWidget = _mapName2DockWidget[name]; 142 | Q_ASSERT(dockWidget); 143 | dockWidget->setVisible(show); 144 | Q_ASSERT(_mapName2Action.contains(name)); 145 | _mapName2Action[name]->setChecked(show); 146 | } 147 | 148 | /// Creates the specified inner dock widget and adds to the QDockWidget 149 | bool MainWindow::_createInnerDockWidget(const QString& widgetName) 150 | { 151 | APLDockWidget* widget = NULL; 152 | QAction *action = _mapName2Action[widgetName]; 153 | if(action) { 154 | switch(action->data().toInt()) { 155 | case DATA_ANALYZE: 156 | widget = new DataAnalyze(widgetName, action, this); 157 | break; 158 | } 159 | if(widget) { 160 | _mapName2DockWidget[widgetName] = widget; 161 | } 162 | } 163 | return widget != NULL; 164 | } 165 | 166 | void MainWindow::resizeEvent(QResizeEvent* event) 167 | { 168 | QMainWindow::resizeEvent(event); 169 | 170 | QWidget * mainWidget=_ui.mainWidget; 171 | QRect resizeRect=mainWidget->rect(); 172 | static float baseWidth=400; 173 | static float baseHeight=300; 174 | static float widgetWidth=resizeRect.width(); 175 | static float widgetHeight=resizeRect.height(); 176 | 177 | float horRatio=this->rect().width()/baseWidth; 178 | float verRatio=this->rect().height()/baseHeight; 179 | 180 | //resize the verticalLayoutWidget 181 | resizeRect.setWidth(widgetWidth*horRatio); 182 | resizeRect.setHeight(widgetHeight*verRatio - 10); 183 | 184 | //set Geometry 185 | mainWidget->setGeometry(resizeRect); 186 | } 187 | 188 | void MainWindow::_fileOpenedTrigger() 189 | { 190 | QTreeWidgetItem* groupItem; 191 | int GroupCount = APLDB::getAPLDB() -> getGroupCount(); 192 | int ItemCount = 0; 193 | int treeGroupCount = 0; 194 | 195 | _groupName.clear(); 196 | 197 | for(int i = 1; i <= GroupCount; i++){ 198 | if(APLDB::getAPLDB() -> isEmpty(APLDB::getAPLDB() -> getGroupName(i)) == false){ 199 | _groupName << QString("%1").arg(APLDB::getAPLDB() -> getGroupName(i)); 200 | treeGroupCount++; 201 | } 202 | } 203 | 204 | _groupName.sort(); 205 | 206 | for(int i = 0; i < treeGroupCount; i++){ 207 | QString table_name = _groupName.at(i); 208 | groupItem = new QTreeWidgetItem(_ui.treeWidget,QStringList(table_name)); 209 | ItemCount = APLDB::getAPLDB() -> getItemCount(table_name); 210 | for (int j = 1; j <= ItemCount; j++) 211 | { 212 | QTreeWidgetItem *item=new QTreeWidgetItem(groupItem,QStringList(APLDB::getAPLDB() -> getItemName(table_name, j))); 213 | item->setCheckState(0, Qt::Unchecked); 214 | groupItem->addChild(item); 215 | } 216 | } 217 | 218 | requestTableList(); 219 | } 220 | 221 | void MainWindow::requestTableList() 222 | { 223 | for(int i=0; i<_ui.treeWidget->topLevelItemCount(); i++){ 224 | emit treeWidgetAddItem(_ui.treeWidget->topLevelItem(i)->text(0)); 225 | } 226 | } 227 | 228 | void MainWindow::setComboboxList(QString table) 229 | { 230 | QString Item0; 231 | QString Item1; 232 | 233 | Item0 = APLDB::getAPLDB()->getItemName(table, 0); 234 | Item1 = APLDB::getAPLDB()->getItemName(table, 1); 235 | if(!_comboBoxList.contains(Item0)){ 236 | _comboBoxList<addItem(Item0); 238 | } 239 | if(!_comboBoxList.contains(Item1)){ 240 | _comboBoxList<addItem(Item1); 242 | } 243 | if(_comboBoxListINIT){ 244 | _comboBoxListINIT = false; 245 | _ui.comboBox->setCurrentIndex(1); 246 | } 247 | } 248 | 249 | void MainWindow::_plotGraph(QTreeWidgetItem *item, int column) 250 | { 251 | QTreeWidgetItem* parent = item->parent(); 252 | QCustomPlot* customPlot = MainWindow::getMainWindow()->ui().customPlot; 253 | int index; 254 | 255 | if(NULL==parent) return; 256 | 257 | index = parent->indexOfChild(item); 258 | _table = parent->text(column); 259 | _field = parent->child(index)->text(column); 260 | 261 | plotGraph(_table, 262 | _field, 263 | 0, 264 | 0, 265 | 1, 266 | 0, 267 | 0, 268 | 0, 269 | true); 270 | 271 | customPlot->replot(); 272 | } 273 | 274 | void MainWindow::_removeGraph(QTreeWidgetItem *item, int column) 275 | { 276 | QTreeWidgetItem* parent = item->parent(); 277 | QCustomPlot* customPlot = MainWindow::getMainWindow()->ui().customPlot; 278 | int index; 279 | 280 | if(NULL==parent) return; 281 | 282 | index = parent->indexOfChild(item); 283 | _table = parent->text(column); 284 | _field = parent->child(index)->text(column); 285 | 286 | QString remove_target = QString("%1.%2").arg(_table).arg(_field); 287 | 288 | QStringList alreadyPloted; 289 | if(_alreadyPloted.contains(remove_target)){ 290 | _alreadyPloted.removeOne(remove_target); 291 | alreadyPloted = _alreadyPloted; 292 | clear_alreadyPloted(); 293 | 294 | if(alreadyPloted.length() == 0){ 295 | _ui.customPlot->legend->setVisible(false); 296 | } 297 | } else { 298 | return; 299 | } 300 | 301 | _ui.customPlot->clearGraphs(); 302 | 303 | for(int i=0; ireplot(); 319 | } 320 | 321 | void MainWindow::clearGraph() 322 | { 323 | clear_alreadyPloted(); 324 | _ui.customPlot->legend->setVisible(false); 325 | _ui.customPlot->clearGraphs(); 326 | _ui.customPlot->replot(); 327 | _clearTreeWidget(_ui.treeWidget); 328 | } 329 | 330 | void MainWindow::clearGraphNotTree() 331 | { 332 | clear_alreadyPloted(); 333 | _ui.customPlot->legend->setVisible(false); 334 | _ui.customPlot->clearGraphs(); 335 | _ui.customPlot->replot(); 336 | // _clearTreeWidget(_ui.treeWidget); 337 | } 338 | 339 | void MainWindow::_resetGraph() 340 | { 341 | _action_bold = (0x1<<0); 342 | _ui.customPlot->axisRect()->setRangeZoomAxes(_ui.customPlot->xAxis, _ui.customPlot->yAxis); 343 | _ui.customPlot->rescaleAxes(); 344 | _ui.customPlot->replot(); 345 | } 346 | 347 | void MainWindow::_zoomX() 348 | { 349 | _action_bold = (0x1<<1); 350 | _ui.customPlot->axisRect()->setRangeZoomAxes(_ui.customPlot->xAxis, NULL); 351 | } 352 | 353 | void MainWindow::_zoomY() 354 | { 355 | _action_bold = (0x1<<2); 356 | _ui.customPlot->axisRect()->setRangeZoomAxes(NULL, _ui.customPlot->yAxis); 357 | } 358 | 359 | void MainWindow::_zoomAll() 360 | { 361 | _action_bold = (0x1<<3); 362 | _ui.customPlot->axisRect()->setRangeZoomAxes(_ui.customPlot->xAxis, _ui.customPlot->yAxis); 363 | } 364 | 365 | void MainWindow::on_customPlot_customContextMenuRequested() 366 | { 367 | QFont ft; 368 | QMenu *menu=new QMenu(_ui.customPlot); 369 | 370 | // Clear graph 371 | QAction* pClearGraph = new QAction(tr("Clear"), this); 372 | connect(pClearGraph, &QAction::triggered, this, &MainWindow::clearGraph); 373 | menu->addAction(pClearGraph); 374 | // Reset graph 375 | QAction* pResetGraph = new QAction(tr("Reset graph"), this); 376 | ft.setBold((_action_bold & 0x1) != 0); 377 | pResetGraph->setFont(ft); 378 | connect(pResetGraph, &QAction::triggered, this, &MainWindow::_resetGraph); 379 | menu->addAction(pResetGraph); 380 | // Zoom X 381 | QAction* pZoomX = new QAction(tr("zoom X"), this); 382 | ft.setBold((_action_bold & 0x2) != 0); 383 | pZoomX->setFont(ft); 384 | connect(pZoomX, &QAction::triggered, this, &MainWindow::_zoomX); 385 | menu->addAction(pZoomX); 386 | // Zoom Y 387 | QAction* pZoomY = new QAction(tr("zoom Y"), this); 388 | ft.setBold((_action_bold & 0x4) != 0); 389 | pZoomY->setFont(ft); 390 | connect(pZoomY, &QAction::triggered, this, &MainWindow::_zoomY); 391 | menu->addAction(pZoomY); 392 | // Zoom All 393 | QAction* pZoomAll = new QAction(tr("Zoom All"), this); 394 | ft.setBold((_action_bold & 0x8) != 0); 395 | pZoomAll->setFont(ft); 396 | connect(pZoomAll, &QAction::triggered, this, &MainWindow::_zoomAll); 397 | menu->addAction(pZoomAll); 398 | menu->exec(QCursor::pos()); 399 | } 400 | 401 | void MainWindow::on_comboBox_currentIndexChanged(const QString &arg1) 402 | { 403 | if(arg1.compare("") == 0) return; 404 | _X_axis_changed = true; 405 | _comboBoxIndex = _ui.comboBox->currentIndex(); 406 | _ui.customPlot->legend->setVisible(false); 407 | _ui.customPlot->clearGraphs(); 408 | _ui.customPlot->xAxis->setLabel(MainWindow::getMainWindow()->ui().comboBox->currentText()); 409 | _ui.customPlot->replot(); 410 | 411 | QStringList alreadyPloted = _alreadyPloted; 412 | clear_alreadyPloted(); 413 | 414 | if(!_replot) return; 415 | 416 | for(int i=0; ireplot(); 432 | } 433 | 434 | void MainWindow::_saveSuccessMessage(){ 435 | QMessageBox::information(this,tr("Information"),tr("Save success")); 436 | } 437 | 438 | void MainWindow::initTreeWidget(){ 439 | _ui.treeWidget->setColumnCount(1); 440 | _ui.treeWidget->setHeaderLabel(tr("ArduPilot Log")); 441 | _ui.treeWidget->setHeaderHidden(true); 442 | 443 | connect(_ui.treeWidget, &QTreeWidget::itemChanged, this, &MainWindow::itemChangedSlot); 444 | } 445 | 446 | bool MainWindow::isTopItem(QTreeWidgetItem *item) 447 | { 448 | if(!item) return false; 449 | if(!item->parent()) return true; 450 | return false; 451 | } 452 | 453 | void MainWindow::setChildCheckState(QTreeWidgetItem *item, Qt::CheckState cs, int column) 454 | { 455 | if(!item) return; 456 | for (int i=0;ichildCount();i++) 457 | { 458 | QTreeWidgetItem* child=item->child(i); 459 | if(child->checkState(0)!=cs) 460 | { 461 | child->setCheckState(0, cs); 462 | } 463 | } 464 | setParentCheckState(item->parent(), column); 465 | } 466 | 467 | void MainWindow::setParentCheckState(QTreeWidgetItem *item, int column) 468 | { 469 | if(!item) return; 470 | int selectedCount=0; 471 | int childCount = item->childCount(); 472 | 473 | if(_plotConf){ 474 | clear_alreadyPloted(); 475 | _ui.customPlot->legend->setVisible(false); 476 | _ui.customPlot->clearGraphs(); 477 | _ui.customPlot->replot(); 478 | _plotConf = false; 479 | } 480 | 481 | for (int i=0;ichild(i); 484 | if(child->checkState(column)==Qt::Checked) 485 | { 486 | selectedCount++; 487 | _plotGraph(item->child(i), column); 488 | } else { 489 | _removeGraph(item->child(i), column); 490 | } 491 | } 492 | 493 | if(selectedCount == 0) { 494 | item->setCheckState(column,Qt::Unchecked); 495 | } else if (selectedCount == childCount) { 496 | item->setCheckState(column,Qt::Checked); 497 | } else { 498 | item->setCheckState(column,Qt::PartiallyChecked); 499 | } 500 | } 501 | 502 | void MainWindow::itemChangedSlot(QTreeWidgetItem *item, int column) 503 | { 504 | if(Qt::PartiallyChecked!=item->checkState(column)){ 505 | if(isTopItem(item) == false) 506 | setChildCheckState(item,item->checkState(column), column); 507 | else 508 | setParentCheckState(item, column); 509 | } 510 | 511 | if(Qt::PartiallyChecked==item->checkState(column)){ 512 | if(!isTopItem(item)){ 513 | item->parent()->setCheckState(column,Qt::PartiallyChecked); 514 | } 515 | } 516 | } 517 | 518 | void MainWindow::_clearTreeWidget(QTreeWidget *treeWidget) 519 | { 520 | for(int i=0; itopLevelItemCount(); i++){ 521 | for (int j=0; j < treeWidget->topLevelItem(i)->childCount(); j++) 522 | { 523 | QTreeWidgetItem* child=treeWidget->topLevelItem(i)->child(j); 524 | child->setCheckState(0, Qt::Unchecked); 525 | } 526 | } 527 | } 528 | 529 | void 530 | MainWindow::plotGraph(QString tables, 531 | QString fields, 532 | int offsetX, 533 | float offsetY, 534 | float scale, 535 | int linestyle, 536 | int color, 537 | bool visible, 538 | bool from) 539 | { 540 | bool getXSuccess = false; 541 | bool getYSuccess = false; 542 | static bool from_last = from; 543 | 544 | if(!from_last && from){ 545 | clear_alreadyPloted(); 546 | _ui.customPlot->legend->setVisible(false); 547 | _ui.customPlot->clearGraphs(); 548 | _ui.customPlot->replot(); 549 | } 550 | from_last = from; 551 | 552 | QCustomPlot* customPlot = MainWindow::getMainWindow()->ui().customPlot; 553 | 554 | QString plot_target = QString("%1.%2").arg(tables).arg(fields); 555 | 556 | if(_is_constant){ 557 | plot_target = QString("const: %1").arg(_constant_value); 558 | } 559 | 560 | if(!_alreadyPloted.contains(plot_target)) 561 | _alreadyPloted << plot_target; 562 | else 563 | return; 564 | 565 | if(visible || from){ 566 | qCDebug(MAIN_WINDOW_LOG) << "from: "<addGraph(); 568 | int length = APLDB::getAPLDB() -> getLen(tables, fields); 569 | QVector x(length), y(length); 570 | 571 | getXSuccess = APLDB::getAPLDB() -> getData(tables, MainWindow::getMainWindow()->ui().comboBox->currentText(), length, x, offsetX); 572 | getYSuccess = APLDB::getAPLDB() -> getData(tables, fields, length, y, offsetY, scale); 573 | 574 | if(_is_constant){ 575 | QVector constant(length, _constant_value); 576 | y.swap(constant); 577 | _is_constant = false; 578 | } 579 | 580 | if(getXSuccess && getYSuccess){ 581 | customPlot->graph()->setData(x, y); 582 | } else { 583 | if(!getXSuccess) 584 | qCDebug(MAIN_WINDOW_LOG) << "getData X Error"; 585 | if(!getYSuccess) 586 | qCDebug(MAIN_WINDOW_LOG) << "getData Y Error"; 587 | } 588 | 589 | customPlot->legend->setVisible(true); 590 | customPlot->legend->setFont(QFont("Helvetica", 9)); 591 | customPlot->legend->setRowSpacing(-3); 592 | customPlot->graph()->setName(plot_target); 593 | 594 | _lineStyle(linestyle, color, from); 595 | 596 | customPlot->xAxis->setLabel(MainWindow::getMainWindow()->ui().comboBox->currentText()); 597 | customPlot->yAxis->setLabel("y"); 598 | customPlot->rescaleAxes(); 599 | 600 | customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); 601 | } 602 | } 603 | 604 | void 605 | MainWindow::_lineStyle(int index, int i, bool from){ 606 | QCustomPlot* customPlot = MainWindow::getMainWindow()->ui().customPlot; 607 | QPen pen; 608 | 609 | if(from && !_conf_plot){ 610 | int R = 0+qrand()%(255-0); 611 | int G = 0+qrand()%(255-0); 612 | int B = 0+qrand()%(255-0); 613 | qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); 614 | pen.setColor(QColor(R, G, B)); 615 | _replot = true; 616 | } else { 617 | pen.setColor(colors[0].at(i)); 618 | _replot = false; 619 | } 620 | 621 | switch (index) { 622 | case 0: // Normal 623 | break; 624 | case 1: // Line1 625 | pen.setWidthF(2); 626 | break; 627 | case 2: // Line2 628 | customPlot->graph()->setBrush(QBrush(QColor(0, 0, 255, 20))); 629 | break; 630 | case 3: // Line3 631 | pen.setWidthF(2); 632 | customPlot->graph()->setBrush(QBrush(QColor(0, 0, 255, 20))); 633 | break; 634 | case 4: // Dot1 635 | pen.setStyle(Qt::DashLine); 636 | break; 637 | case 5: // Dot2 638 | pen.setStyle(Qt::DotLine); 639 | pen.setWidthF(2); 640 | break; 641 | case 6: // Dot3 642 | pen.setStyle(Qt::DashDotLine); 643 | customPlot->graph()->setBrush(QBrush(QColor(0, 255, 0, 20))); 644 | break; 645 | case 7: // Mark1 646 | pen.setWidthF(1); 647 | customPlot->graph()->setScatterStyle(QCPScatterStyle(shapes[0].at(0))); 648 | break; 649 | case 8: // Mark2 650 | pen.setWidthF(1); 651 | customPlot->graph()->setScatterStyle(QCPScatterStyle(shapes[0].at(1))); 652 | break; 653 | case 9: // Mark3 654 | customPlot->graph()->setLineStyle(QCPGraph::lsNone); 655 | customPlot->graph()->setScatterStyle(QCPScatterStyle(shapes[0].at(0))); 656 | break; 657 | default: // Normal 658 | break; 659 | } 660 | customPlot->graph()->setPen(pen); 661 | } 662 | 663 | bool 664 | MainWindow::_findTable(QString table) 665 | { 666 | // qCDebug(MAIN_WINDOW_LOG) << _groupName; 667 | if(_groupName.contains(table)){ 668 | // qCDebug(MAIN_WINDOW_LOG) << "find table"; 669 | return true; 670 | } 671 | 672 | qCDebug(MAIN_WINDOW_LOG) << "can not find table"; 673 | return false; 674 | } 675 | 676 | bool 677 | MainWindow::_findField(QString table, QString field) 678 | { 679 | if(_is_constant) return true; 680 | 681 | int ItemCount = APLDB::getAPLDB() -> getItemCount(table); 682 | for (int j = 1; j <= ItemCount; j++) 683 | { 684 | if(APLDB::getAPLDB() -> getItemName(table, j).compare(field) == 0){ 685 | // qCDebug(MAIN_WINDOW_LOG) << "find field"; 686 | return true; 687 | } 688 | } 689 | 690 | qCDebug(MAIN_WINDOW_LOG) << "can not find field"; 691 | return false; 692 | } 693 | 694 | void MainWindow::_confOpenedTrigger() 695 | { 696 | QList list; 697 | 698 | _ui.splitter->setSizes(list<<0<<1); 699 | _conf_plot = true; 700 | 701 | clear_alreadyPloted(); 702 | 703 | plotConf(_conf); 704 | } 705 | 706 | void 707 | MainWindow::plotConf(QStringList conf) 708 | { 709 | QString table; 710 | QString field; 711 | QString style; 712 | QString color; 713 | QString scale("1"); 714 | QString offsetX("0"); 715 | QString offsetY("0"); 716 | 717 | clearGraphNotTree(); 718 | _plotConf = true; 719 | 720 | for(int i=0; i\\s*[A-Za-Z0-9]+\\:\\-?\\d+\\.?\\d*\\s+\\d\\.\\d"); 725 | QRegExpValidator validator_1(reg_1,0); 726 | QRegExpValidator validator_2(reg_2,0); 727 | QRegExpValidator validator_3(reg_3,0); 728 | bool check_ok = false; 729 | 730 | int pos = 0; 731 | 732 | if(reg_1.isValid() && !check_ok){ 733 | switch(validator_1.validate(str,pos)){ 734 | case QValidator::Invalid: 735 | qCDebug(MAIN_WINDOW_LOG)<<"reg_1 QValidator::Invalid"; 736 | break; 737 | case QValidator::Intermediate:{ 738 | qCDebug(MAIN_WINDOW_LOG)<<"reg_1 QValidator::Intermediate"; 739 | QStringList list = str.split("."); 740 | table = list[0]; 741 | field = list[1]; 742 | if(str.count(".")==1){ 743 | str.append(".0.0"); 744 | } 745 | break; 746 | } 747 | case QValidator::Acceptable:{ 748 | QStringList list = str.split("."); 749 | table = list[0]; 750 | field = list[1]; 751 | style = list[2]; 752 | color = list[3]; 753 | 754 | check_ok = true; 755 | 756 | break; 757 | } 758 | } 759 | } 760 | 761 | if(reg_2.isValid() && !check_ok){ 762 | switch(validator_2.validate(str,pos)){ 763 | case QValidator::Invalid: 764 | qCDebug(MAIN_WINDOW_LOG)<<"reg_2 QValidator::Invalid"; 765 | break; 766 | case QValidator::Intermediate: 767 | qCDebug(MAIN_WINDOW_LOG)<<"reg_2 QValidator::Intermediate"; 768 | break; 769 | case QValidator::Acceptable:{ 770 | QString table_filed_style_color(str.left(str.indexOf("("))); 771 | QStringList list_1 = table_filed_style_color.split("."); 772 | table = list_1[0]; 773 | field = list_1[1]; 774 | style = list_1[2]; 775 | color = list_1[3]; 776 | 777 | QString scale_offsetX_offsetY(str.mid(str.indexOf("(")+1, str.indexOf(")")-str.indexOf("(")-1).remove(QRegExp("\\s"))); 778 | QStringList list = scale_offsetX_offsetY.split(","); 779 | scale = list[0]; 780 | offsetX = list[1]; 781 | offsetY = list[2]; 782 | 783 | check_ok = true; 784 | 785 | break; 786 | } 787 | } 788 | } 789 | 790 | if(reg_3.isValid() && !check_ok){ 791 | switch(validator_3.validate(str,pos)){ 792 | case QValidator::Invalid: 793 | qCDebug(MAIN_WINDOW_LOG)<<"reg_3 QValidator::Invalid"; 794 | break; 795 | case QValidator::Intermediate: 796 | qCDebug(MAIN_WINDOW_LOG)<<"reg_3 QValidator::Intermediate"; 797 | break; 798 | case QValidator::Acceptable:{ 799 | qCDebug(MAIN_WINDOW_LOG)<<"reg_3 QValidator::Acceptable"; 800 | QString command_str(str.simplified()); 801 | QString command = command_str.mid(command_str.indexOf("<")+1, command_str.indexOf(">")-command_str.indexOf("<")-1); 802 | if(command.compare("const")==0 || command.compare("")==0){ 803 | QStringList list = command_str.split(QRegExp("[:\\s]")); 804 | table = list[1]; 805 | field = MainWindow::getMainWindow()->ui().comboBox->currentText(); 806 | QString constant_value = list[2]; 807 | QString style_color = list[3]; 808 | QStringList style_color_list = style_color.split("."); 809 | style = style_color_list[0]; 810 | color = style_color_list[1]; 811 | _constant_value = constant_value.toDouble(); 812 | 813 | _is_constant = true; 814 | } 815 | 816 | check_ok = true; 817 | 818 | break; 819 | } 820 | } 821 | } 822 | 823 | if(_findTable(table)){ 824 | if(_findField(table, field)){ 825 | plotGraph(table, 826 | field, 827 | offsetX.toInt(), 828 | offsetY.toFloat(), 829 | scale.toFloat(), 830 | style.toInt(), 831 | color.toInt(), 832 | 0, 833 | true); 834 | } 835 | } 836 | } 837 | _ui.customPlot->replot(); 838 | 839 | _conf_plot = false; 840 | } 841 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "ui_mainwindow.h" 6 | 7 | #include "APLLoggingCategory.h" 8 | #include "APLDockWidget.h" 9 | #include "src/Dialog.h" 10 | #include "src/DialogLoad.h" 11 | #include "qcustomplot.h" 12 | 13 | Q_DECLARE_LOGGING_CATEGORY(MAIN_WINDOW_LOG) 14 | 15 | class MainWindow : public QMainWindow 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | explicit MainWindow(QWidget *parent = 0); 21 | ~MainWindow(); 22 | 23 | static bool get_customPlot_hold_on() { return _customPlot_hold_on; } 24 | static int get_comboBoxIndex() { return _comboBoxIndex; } 25 | static bool get_X_axis_changed() { return _X_axis_changed; } 26 | static void set_X_axis_changed(bool b) { _X_axis_changed = b; } 27 | static MainWindow* getMainWindow() { return _instance; } 28 | Ui::MainWindow& ui() { return _ui; } 29 | void requestTableList(); 30 | void closeEvent(QCloseEvent * event); 31 | 32 | void initTreeWidget(); 33 | bool isTopItem(QTreeWidgetItem* item); 34 | void setChildCheckState(QTreeWidgetItem *item, Qt::CheckState cs, int column); 35 | void setParentCheckState(QTreeWidgetItem *item, int column); 36 | void set_conf(QStringList conf) { _conf = conf; } 37 | 38 | QVector shapes[10]; 39 | QVector colors[10]; 40 | 41 | public slots: 42 | void resizeEvent(QResizeEvent* event); 43 | void itemChangedSlot(QTreeWidgetItem* item, int column); 44 | void setComboboxList(QString table); 45 | void plotGraph(QString tables, 46 | QString fields, 47 | int offsetX, 48 | float offsetY, 49 | float scale, 50 | int linestyle, 51 | int color, 52 | bool visible, 53 | bool from); // false:DataAnalyzeController,true:Other 54 | void clear_alreadyPloted() { _alreadyPloted.clear(); } 55 | void clearGraph(); 56 | void clearGraphNotTree(); 57 | void plotConf(QStringList conf); 58 | 59 | private slots: 60 | void _showDockWidgetAction(bool show); 61 | void _plotGraph(QTreeWidgetItem *item, int column); 62 | void _removeGraph(QTreeWidgetItem *item, int column); 63 | void _resetGraph(); 64 | void _zoomX(); 65 | void _zoomY(); 66 | void _zoomAll(); 67 | void on_customPlot_customContextMenuRequested(); 68 | void on_comboBox_currentIndexChanged(const QString &arg1); 69 | void _saveSuccessMessage(); 70 | void _confOpenedTrigger(); 71 | 72 | signals: 73 | void treeWidgetAddItem(QString name); 74 | 75 | private: 76 | Ui::MainWindow _ui; 77 | Dialog* _dialog; 78 | DialogLoad* _dialog_load; 79 | static bool _customPlot_hold_on; 80 | static int _comboBoxIndex; 81 | static bool _X_axis_changed; 82 | static MainWindow* _instance; 83 | QString _table; 84 | QString _field; 85 | QStringList _comboBoxList; 86 | QStringList _alreadyPloted; 87 | QStringList _groupName; 88 | QStringList _conf; 89 | bool _comboBoxListINIT; 90 | bool _conf_plot; 91 | bool _is_constant; 92 | bool _replot; 93 | bool _plotConf; 94 | double _constant_value; 95 | int _action_bold; 96 | 97 | QMap _mapName2DockWidget; 98 | QMap _mapName2Action; 99 | 100 | void _buildCommonWidgets(void); 101 | void _showDockWidget(const QString &name, bool show); 102 | bool _createInnerDockWidget(const QString& widgetName); 103 | void _fileOpenedTrigger(); 104 | void _clearTreeWidget(QTreeWidget *treeWidget); 105 | void _lineStyle(int index, int i, bool from); 106 | bool _findTable(QString table); 107 | bool _findField(QString table, QString field); 108 | }; 109 | 110 | #endif // MAINWINDOW_H 111 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | :/res/resources/icons/ardupilotlog.ico:/res/resources/icons/ardupilotlog.ico 19 | 20 | 21 | 22 | 23 | 0 24 | 0 25 | 26 | 27 | 28 | 29 | 30 | 0 31 | 0 32 | 400 33 | 295 34 | 35 | 36 | 37 | 38 | 0 39 | 0 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 0 48 | 0 49 | 50 | 51 | 52 | Qt::Horizontal 53 | 54 | 55 | 56 | 57 | 5 58 | 59 | 60 | 61 | 62 | 63 | 1 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 5 74 | 75 | 76 | 77 | 78 | 79 | 80 | X Axis 81 | 82 | 83 | 84 | 85 | 86 | 87 | Qt::ActionsContextMenu 88 | 89 | 90 | 91 | 92 | 93 | 94 | Qt::Horizontal 95 | 96 | 97 | 98 | 40 99 | 20 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | Qt::CustomContextMenu 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 0 132 | 0 133 | 800 134 | 26 135 | 136 | 137 | 138 | 139 | File 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | Tools 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | Open ArduPilotLog 159 | 160 | 161 | 162 | 163 | Exit 164 | 165 | 166 | 167 | 168 | Save DB file 169 | 170 | 171 | 172 | 173 | Load 174 | 175 | 176 | 177 | 178 | 179 | 180 | QCustomPlot 181 | QWidget 182 |
qcustomplot.h
183 | 1 184 |
185 |
186 | 187 | 188 | 189 | 190 |
191 | -------------------------------------------------------------------------------- /matlab/APMBinaryLog.m: -------------------------------------------------------------------------------- 1 | function APMBinaryLog 2 | eval('clc'); 3 | disp('clear all'); 4 | disp('waiting ...'); 5 | LOG_FORMAT_MSG = 128; 6 | 7 | % #define HEAD_BYTE1 0xA3 // Decimal 163 8 | % #define HEAD_BYTE2 0x95 // Decimal 149 9 | HEAD_BYTE1 = 163; 10 | HEAD_BYTE2 = 149; 11 | 12 | % struct LogStructure { 13 | % uint8_t msg_type; 14 | % uint8_t msg_len; 15 | % const char name[5]; 16 | % const char format[16]; 17 | % const char labels[64]; 18 | % }; 19 | NameLength = 4; 20 | FormatLength = 16; 21 | LabelLength = 64; 22 | 23 | fid = -1; 24 | [filename, pathname] = uigetfile({'*.db';'*.bin';'*.*'}, 'Open log file'); 25 | fullname = strcat(char(pathname), char(filename)); 26 | if isempty(fullname) 27 | return; 28 | end 29 | split_file_name = regexp(filename, '\.', 'split'); 30 | if strcmp(split_file_name(1, size(split_file_name,2)), 'db') == 1 31 | disp('Do not recognize Chinese path !!!'); 32 | conn = sqlite(fullname, 'readonly'); 33 | group_name = fetch(conn,'SELECT name FROM maintable'); 34 | labels = fetch(conn,'SELECT labels FROM maintable'); 35 | names={}; 36 | tic; 37 | for i = 1:size(group_name, 1) 38 | valid_group = cell2mat(eval(strcat('fetch(conn,','''SELECT COUNT(*) FROM', 32, char(group_name{i}),''')'))); 39 | if valid_group == 0 40 | continue; 41 | else 42 | eval(strcat('content=', 'fetch(conn,','''SELECT * FROM', 32, char(group_name{i}),''');')); 43 | C={}; FIELDS={}; 44 | colums = size(content,2); 45 | for j = 1:colums 46 | if isnumeric(content{1, j}) 47 | C{j} = double(cell2mat(content(:, j))); 48 | else 49 | C{j} = content(:, j); 50 | end 51 | end 52 | FIELDS = regexp(char(labels(i,1)), ',', 'split'); 53 | C = C(:,2:size(C,2)); 54 | eval(strcat(lower(char(group_name{i})),'=cell2struct(C,FIELDS,2);')); 55 | eval(char(strcat('assignin(','''','base','''',', ','''',char(lower(char(group_name{i}))),'''',',', char(lower(char(group_name{i}))), ');'))); 56 | names {numel(names) +1, 1} = lower(char(group_name{i})); 57 | end 58 | end 59 | close(conn); 60 | toc; 61 | assignin('base','names',sort(names)); 62 | clear C colums content group_name i j labels valid_group FIELDS; 63 | 64 | else 65 | 66 | fid = fopen(fullname, 'rb'); 67 | if fid == -1 68 | return; 69 | end 70 | fsize = 0; 71 | if(fid > 0) 72 | fseek(fid, 0, 1); 73 | fsize = ftell(fid); 74 | fseek(fid, 0, -1); 75 | end 76 | 77 | types={}; lengths={}; names={}; formats={}; labels={};values={};log={}; 78 | c_last = zeros(3, 1); 79 | 80 | % tic; % tic1 81 | % first read find all FMT 82 | while ftell(fid) < fsize 83 | c = fread(fid, 1); 84 | ptr_pos = ftell(fid); 85 | if ptr_pos > 3 86 | c_last(1) = c_last(2); 87 | c_last(2) = c_last(3); 88 | c_last(3) = c; 89 | else 90 | switch ptr_pos 91 | case 1 92 | c_last(1) = c; 93 | continue; 94 | case 2 95 | c_last(2) = c; 96 | continue; 97 | case 3 98 | c_last(3) = c; 99 | end 100 | end 101 | 102 | if isequal(c_last(1:2, 1),[HEAD_BYTE1; HEAD_BYTE2]) 103 | if c_last(3) == LOG_FORMAT_MSG % Find FMT format infomation 104 | type = fread(fid, 1); 105 | length = fread(fid, 1); 106 | name = strtrim(cellstr(char(fread(fid, NameLength)'))); 107 | format = strtrim(cellstr(char(fread(fid, FormatLength)'))); 108 | label = strtrim(strcat(cellstr(char(fread(fid, LabelLength)')), ',n')); 109 | value = {}; 110 | if any(strcmp(name,names)) 111 | continue; 112 | else 113 | types {numel(types) +1, 1} = type; 114 | lengths{numel(lengths)+1, 1} = length; 115 | names {numel(names) +1, 1} = name; 116 | formats{numel(formats)+1, 1} = format; 117 | labels {numel(labels) +1, 1} = char2cell(char(label),[',']); 118 | values {numel(values) +1, 1} = value; 119 | log = [types, lengths, names, formats, labels, values]; 120 | end 121 | else 122 | continue; 123 | end 124 | end 125 | end 126 | 127 | % eval('clc'); 128 | % disp(['first read time consuming:', num2str(toc),'(s)']); 129 | % tic; % tic2 130 | 131 | % re-read log file 132 | fseek(fid, 0, -1); 133 | num = 0; 134 | 135 | while ftell(fid) < fsize 136 | c = fread(fid, 1); 137 | ptr_pos = ftell(fid); 138 | if ptr_pos > 3 139 | c_last(1) = c_last(2); 140 | c_last(2) = c_last(3); 141 | c_last(3) = c; 142 | else 143 | switch ptr_pos 144 | case 1 145 | c_last(1) = c; 146 | continue; 147 | case 2 148 | c_last(2) = c; 149 | continue; 150 | case 3 151 | c_last(3) = c; 152 | end 153 | end 154 | 155 | if isequal(c_last(1:2, 1),[HEAD_BYTE1; HEAD_BYTE2]) 156 | if c_last(3) == LOG_FORMAT_MSG % Find FMT format infomation 157 | continue; 158 | end 159 | row_num = find(c_last(3)==cell2mat(log(:,1))); 160 | if ~isempty(row_num) % If the ID already in the list 161 | format = strtrim(cellstr(log{row_num, 4})); 162 | format_str = format{1}; 163 | 164 | format_len = size(format_str, 2); 165 | value = {}; 166 | for i = 1: format_len 167 | switch format_str(i) 168 | case 'b' % b : int8_t 169 | value{i} = fread(fid, 1, 'int8'); 170 | if isempty(value{i}) 171 | value{i} = 0; 172 | end 173 | case 'B' % B : uint8_t 174 | value{i} = fread(fid, 1, 'uint8'); 175 | if isempty(value{i}) 176 | value{i} = 0; 177 | end 178 | case 'h' % h : int16_t 179 | value{i} = fread(fid, 1, 'int16'); 180 | if isempty(value{i}) 181 | value{i} = 0; 182 | end 183 | case 'H' % H : uint16_t 184 | value{i} = fread(fid, 1, 'uint16'); 185 | if isempty(value{i}) 186 | value{i} = 0; 187 | end 188 | case 'i' % i : int32_t 189 | value{i} = fread(fid, 1, 'int32'); 190 | if isempty(value{i}) 191 | value{i} = 0; 192 | end 193 | case 'I' % I : uint32_t 194 | value{i} = fread(fid, 1, 'uint32'); 195 | if isempty(value{i}) 196 | value{i} = 0; 197 | end 198 | case 'f' % f : float 199 | value{i} = fread(fid, 1, 'single'); 200 | if isempty(value{i}) 201 | value{i} = 0; 202 | end 203 | case 'd' % d : double 204 | value{i} = fread(fid, 1, 'double'); 205 | if isempty(value{i}) 206 | value{i} = 0; 207 | end 208 | case 'n' % n : char[4] 209 | value{i} = strtrim(cellstr(fread(fid, 4, 'uint8=>char')')); 210 | case 'N' % N : char[16] 211 | value{i} = strtrim(cellstr(fread(fid, 16, 'uint8=>char')')); 212 | case 'Z' % Z : char[64] 213 | value{i} = strtrim(cellstr(fread(fid, 64, 'uint8=>char')')); 214 | case 'c' % c : int16_t * 100 215 | value{i} = fread(fid, 1, 'int16')/100; 216 | if isempty(value{i}) 217 | value{i} = 0; 218 | end 219 | case 'C' % C : uint16_t * 100 220 | value{i} = fread(fid, 1, 'uint16')/100; 221 | if isempty(value{i}) 222 | value{i} = 0; 223 | end 224 | case 'e' % e : int32_t * 100 225 | value{i} = fread(fid, 1, 'int32')/100; 226 | if isempty(value{i}) 227 | value{i} = 0; 228 | end 229 | case 'E' % E : uint32_t * 100 230 | value{i} = fread(fid, 1, 'uint32')/100; 231 | if isempty(value{i}) 232 | value{i} = 0; 233 | end 234 | case 'L' % L : int32_t latitude/longitude 235 | value{i} = fread(fid, 1, 'int32'); 236 | if isempty(value{i}) 237 | value{i} = 0; 238 | end 239 | case 'M' % M : uint8_t flight mode 240 | value{i} = fread(fid, 1, 'uint8'); 241 | if isempty(value{i}) 242 | value{i} = 0; 243 | end 244 | case 'q' % q : int64_t 245 | value{i} = fread(fid, 1, 'int64'); 246 | if isempty(value{i}) 247 | value{i} = 0; 248 | end 249 | case 'Q' % Q : uint64_t 250 | value{i} = fread(fid, 1, 'uint64'); 251 | if isempty(value{i}) 252 | value{i} = 0; 253 | end 254 | end 255 | end 256 | num = num +1; 257 | value{i+1} = num; 258 | log{row_num, 6}(size(log{row_num, 6},1)+1,:) = value; 259 | end 260 | end 261 | end 262 | fclose(fid); 263 | 264 | % disp(['second read time consuming:', num2str(toc),'(s)']); 265 | % tic; % tic3 266 | 267 | val_names={}; 268 | for i = 1: size(log,1) 269 | if isempty(log{i, 6}) 270 | continue; 271 | else 272 | C={}; FIELDS={}; 273 | for j = 1: size(log{i, 5},1) 274 | C{j}=log{i, 6}(:, j); 275 | FIELDS{j}=char(log{i, 5}(j)); 276 | end 277 | eval(strcat(lower(char(log{i, 3})),'=cell2struct(C,FIELDS,2);')); 278 | if ~isequal(char(log{i, 3}), 'PARM') && ~isequal(char(log{i, 3}), 'MSG') 279 | val_names{numel(val_names)+1, 1} = lower(char(log{i, 3})); 280 | end 281 | log{i, 7}(1,1) = strfind(log{i, 4}, 'n'); 282 | log{i, 7}(1,2) = strfind(log{i, 4}, 'N'); 283 | log{i, 7}(1,3) = strfind(log{i, 4}, 'Z'); 284 | for j = 1: size(char(log{i, 4}), 2)+1 % Additional num 285 | if ~isempty(find(j == cell2mat(log{i, 7}(1,1)))) 286 | continue; 287 | else if ~isempty(find(j == cell2mat(log{i, 7}(1,2)))) 288 | continue; 289 | else if ~isempty(find(j == cell2mat(log{i, 7}(1,3)))) 290 | continue; 291 | else 292 | eval(char(strcat(lower(log{i, 3}),'.',char(log{i, 5}(j, 1)),' = cell2mat(',lower(log{i, 3}),'.', char(log{i, 5}(j, 1)),');'))); 293 | end 294 | end 295 | end 296 | end 297 | end 298 | end 299 | 300 | % disp(['Arrangement data time consuming:', num2str(toc),'(s)']); 301 | % tic; % tic4 302 | 303 | arm_time_us = 0; 304 | disarm_time_us = 0; 305 | if exist('ev') 306 | for i = 1: size(ev.TimeUS, 1) 307 | if isequal(ev.Id(i), 10) 308 | arm_time_us = ev.TimeUS(i); 309 | end 310 | if isequal(ev.Id(i), 11) || isequal(ev.Id(i), 17) || isequal(ev.Id(i), 18) 311 | disarm_time_us = ev.TimeUS(i); 312 | end 313 | end 314 | end 315 | 316 | find_time_end_by_rcou = false; 317 | time_ref = 0; 318 | if exist('rcou') 319 | if ~isempty(find(contains(fieldnames(rcou),'C1')==1)) 320 | for i = 1: size(rcou.TimeUS, 1) 321 | if ~isequal(rcou.C1(i), rcou.C2(i), rcou.C3(i), rcou.C4(i)) 322 | time_ref = rcou.TimeUS(i); 323 | end 324 | if isequal(rcou.C1(i), rcou.C2(i), rcou.C3(i), rcou.C4(i)) && ~find_time_end_by_rcou && time_ref > 0 325 | disarm_time_us = rcou.TimeUS(i); 326 | find_time_end_by_rcou = true; 327 | end 328 | end 329 | end 330 | end 331 | 332 | fly_time_us = disarm_time_us - arm_time_us; 333 | fly_time_min = floor(fly_time_us/(60 * 1e6)); 334 | fly_time_s = fly_time_us/1e6 - fly_time_min * 60; 335 | eval('clc'); 336 | if fly_time_us > 0 337 | disp(['fly time: ', num2str(fly_time_min),' min ', num2str(fly_time_s), ' s']); 338 | else 339 | disp(['can not find end timestamp']); 340 | end 341 | 342 | % disp(['calc fly time cost:', num2str(toc),'(s)']); 343 | 344 | % if this script run as a fuction, then below is useful. 345 | for i = 1: size(log, 1) 346 | if isempty(log{i, 6}) 347 | continue; 348 | else 349 | eval(char(strcat('assignin(','''','base','''',', ','''',char(lower(char(log{i, 3}))),'''',',', char(lower(char(log{i, 3}))), ');'))); 350 | end 351 | end 352 | assignin('base','log',log); 353 | assignin('base','names',sort(val_names)); 354 | end 355 | end 356 | -------------------------------------------------------------------------------- /matlab/FSMAnalysis.m: -------------------------------------------------------------------------------- 1 | for i = 1:size(stat.id,1) 2 | FSM_label{stat.id(i, 1)+1, 1} = sprintf('%s%d','id',stat.id(i, 1)); 3 | FSM(stat.id(i, 1)+1, 1) = stat.id(i, 1); 4 | end 5 | C = cell(2, size(FSM_label, 1)); 6 | for i = 1:1:size(stat.id,1) 7 | C{1, stat.id(i, 1)+1}(size(C{1, stat.id(i, 1)+1}, 1)+1,1) = stat.TimeUS(i, 1); 8 | C{2, stat.id(i, 1)+1}(size(C{2, stat.id(i, 1)+1}, 1)+1,1) = stat.stat(i, 1); 9 | end 10 | 11 | state = cell2struct(C, FSM_label, 2); 12 | 13 | h = axes(); 14 | hold on; 15 | leg=[]; 16 | plot_count = 0; 17 | color = rand(size(FSM_label, 1), 3); 18 | except = []; % fill except ids here 19 | axis_x = 1; % 1-n as X axis 2-TimeUS as X axis 20 | times = 1; % FSM value times 21 | for i = 1:size(FSM_label, 1) 22 | if ~isempty(find(FSM(i,1)==except)) 23 | continue 24 | end 25 | plot(h, eval(sprintf('%s%d%s%d','state(',axis_x,').id',FSM(i,1))), eval(sprintf('%s%d','state(2).id',FSM(i,1)))*times,'Color',color(i,:),'Marker','o','MarkerFaceColor',color(i,:),'LineStyle','--'); 26 | plot_count = plot_count + 1; 27 | if(isequal(plot_count,1)) 28 | leg = strcat('''','id',sprintf('%d',FSM(i,1)),''''); 29 | else 30 | leg = strcat(leg,',','''','id',sprintf('%d',FSM(i,1)),''''); 31 | end 32 | end 33 | clc 34 | eval(strcat('legend','(',leg,')')); 35 | grid on 36 | title('Finite State Machine Analysis'); -------------------------------------------------------------------------------- /matlab/ReadMe.md: -------------------------------------------------------------------------------- 1 | 使用方法 2 | --- 3 | 1. Matlab进入脚本目录并运行 4 |
![ArduPilotLog_matlab_1.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_matlab_1.png)
5 | 6 | 2. 加载`\*.db`数据库文件 7 | >
\*.db 数据库文件来源于ArduPilotLog软件:File -> Save DB file
8 | >
*.db 的加载速度比 *.bin 快**数十倍**,且文件越大加载速度差别越明显。
9 | 10 |
![ArduPilotLog_matlab_2.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_matlab_2.png)
11 | 12 | 3. 使用载入 MATLAB 数据的方法 13 | > 例:att.Roll 14 | 15 |
![ArduPilotLog_matlab_3.png](https://github.com/SuWeipeng/img/raw/master/1_ArduPilotLog/ArduPilotLog_matlab_3.png)
16 | -------------------------------------------------------------------------------- /matlab/char2cell.m: -------------------------------------------------------------------------------- 1 | function s = char2cell(s,delim,rowseparate,trim) 2 | % Syntax: cellmat = char2cell(s,delim,rowseparate,trim); 3 | % cellmat = char2cell(s,delim,rowseparate); 4 | % cellmat = char2cell(s,delim); 5 | % cellmat = char2cell(s); 6 | % CHARacter array 2(to) CELL array conversion. 7 | % "s" - Input character array or cell array of strings. 8 | % "delim" - Array or cell array of delimiters. 9 | % If an array then each element is a single element delimeter. 10 | % If a cell array then each cell element is a delimeter or multi-element delimeter. 11 | % The following may be used for non-printing characters: 12 | % (as these characters require 2 elements, they must be specified in a cell array) 13 | % \b - backspace 14 | % \f - formfeed 15 | % \n - linefeed 16 | % \r - carriage return 17 | % \t - tab 18 | % \\ - backslash 19 | % (a single \ suffices if it is a single or last element) 20 | % Use ' ' to specify a white space character. 21 | % Default delimiter is white space if "rowseparate" is empty and is empty 22 | % if "rowseparate" is either "true" or "false". 23 | % "rowseparate" - "true" designates that each row should be separated or 24 | % "false" if each column should be separated. Only relevant if "s" is 25 | % multidimensional. Higher dimensions are wrapped into rows or columns 26 | % depending upon "rowseparate". If "empty", then all matrices are treated as 1D. 27 | % e.g. a KxMxN matrix is treated as a Kx(MxN) matrix if "false" 28 | % or as a Mx(KxN) if "true". 29 | % If a delimeter(s) is specified then both conditions are used. 30 | % "rowseparate" is ignored if "s" is a cell array. 31 | % "trim" - if "true" (default), leading and trailing spaces are deleted 32 | % "cellmat" - Output (1D) cell array. 33 | % 34 | % See Also: cellstr, mat2cell, num2cell, cell2mat 35 | % Examples: 36 | % char2cell(['red? green33 blue++ '],['?3+'])) 37 | % ans = 'red'; 'green'; 'blue'; '' 38 | % c=sprintf(['this is a test\nthis\tis the second line']) 39 | % char2cell(c,{'\n','\t'}) 40 | % ans = 'this is a test' 41 | % 'this' 42 | % 'is the second line' 43 | 44 | % Copyright 2009 Mirtech, Inc. 45 | % Created by Mirko Hrovat 07/17/2009 46 | % Inspired by str2cell.m (File Exchange #4247) by us 47 | %------------------------------------------------------------------------------------ 48 | 49 | ws = ' '; % whitespace 50 | bspc = 8; % \b 51 | ff = 12; % \f 52 | lf = 10; % \n 53 | cr = 13; % \r 54 | tb = 9; % \t 55 | bs = 92; % \\ 56 | del = 127; %#ok - currently not used, delete 57 | spc = 32; % space 58 | bell = 8; %#ok - currently not used, bell 59 | def_delim = ws; % default delimiter 60 | def_trim = true; % default trim value 61 | switch nargin 62 | case 4 63 | case 3 64 | trim = []; 65 | case 2 66 | trim = []; rowseparate = []; 67 | case 1 68 | trim = []; rowseparate = []; delim = []; 69 | otherwise 70 | error (' Number of input arguments incorrect!') 71 | end 72 | if isempty(trim), trim = def_trim; end 73 | if ~ischar(s)&&~iscellstr(s), 74 | error (' Input array must be a character or cell string array!') 75 | end 76 | if ~iscellstr(s), 77 | if isempty(rowseparate) || size(s,1)==1 || size(s,2)==1, 78 | s = shiftdim(s(:),-1); % convert to row of characters 79 | rowseparate = []; 80 | else 81 | if ~rowseparate, 82 | s = permute(s,[2,1]); 83 | end 84 | s = s(:,:); % make s a 2D array 85 | s = cellstr(s); % now convert rows to cells 86 | end 87 | if isempty(rowseparate) && isempty(delim), 88 | delim = def_delim; 89 | end 90 | else 91 | if isempty(delim), delim = def_delim; end 92 | end 93 | if ~isempty(delim), 94 | if ~iscell(delim), delim = num2cell(delim); end 95 | strtidx = []; 96 | stopidx = []; 97 | for n = 1:numel(delim), 98 | mpts = numel(delim{n}); 99 | searchchar = char(ones(1,mpts)*spc); 100 | m = 0; 101 | nschars = 0; 102 | while m < mpts, 103 | m = m + 1; 104 | curchar = delim{n}(m); 105 | if curchar=='\' 106 | m = m + 1; 107 | if m <= mpts, 108 | curchar = delim{n}(m); 109 | switch curchar 110 | case 'b' % backspace 111 | curchar = char(bspc); 112 | case 'f' % formfeed 113 | curchar = char(ff); 114 | case 'n' % linefeed 115 | curchar = char(lf); 116 | case 'r' % return 117 | curchar = char(cr); 118 | case 't' % tab 119 | curchar = char(tb); 120 | case '\' % backslash 121 | curchar = char(bs); 122 | otherwise 123 | error(' Special character not recognized, e.g. \n !') 124 | end 125 | else % backslash is a single element or is last element 126 | curchar = char(bs); % so intepret it as a backslash 127 | end 128 | end 129 | nschars = nschars + 1; 130 | searchchar(nschars) = curchar; 131 | end 132 | searchchar(nschars+1:end) = []; 133 | tmp = strfind(s,searchchar); % find matching indices 134 | if iscell(tmp), 135 | stopidx = strcat(stopidx,tmp); % combine results 136 | tmp2 = num2cell(ones(size(s))*nschars); 137 | % add delimiter length to get next starting indices 138 | tmp2 = cellfun(@plus,tmp,tmp2,'UniformOutput',false); 139 | strtidx = strcat(strtidx,tmp2); % combine results 140 | else 141 | stopidx = [stopidx,tmp]; %#ok combine results 142 | tmp2 = tmp + nschars; % add delimiter length 143 | strtidx = [strtidx,tmp2]; %#ok 144 | end 145 | end 146 | 147 | % now use strt and stop idx to create cells 148 | if iscell(s), 149 | ncells = sum(cellfun(@numel,strtidx)); % find total number of indices 150 | scells = size(s,1); 151 | tmp = cell(ncells,1); 152 | count = 0; 153 | for m = 1:scells, 154 | startpt = 1; 155 | strt = sort(strtidx{m}); 156 | stop = sort(stopidx{m}); 157 | for p=1:numel(strt), 158 | if stop(p)>startpt, 159 | count = count + 1; 160 | tmp{count} = s{m}(startpt:stop(p)-1); 161 | end 162 | startpt = strt(p); 163 | end 164 | if startpt <= numel(s{m}), % need to extract the rest of the array 165 | count = count + 1; 166 | tmp{count} = s{m}(startpt:end); 167 | end 168 | end 169 | else % s is not a cell array 170 | strt = sort(strtidx); 171 | stop = sort(stopidx ); 172 | ncells = numel(strtidx); 173 | tmp = cell(ncells+1,1); 174 | startpt = 1; 175 | count = 0; 176 | for m = 1:ncells 177 | if stop(m) > startpt, 178 | count = count + 1; 179 | tmp{count}= s(startpt:stop(m)-1); 180 | end 181 | startpt = strt(m); 182 | end 183 | if startpt <= numel(s), % need to extract the rest of the array 184 | count = count + 1; 185 | tmp{count} = s(startpt:end); 186 | end 187 | end 188 | s = tmp(1:count); 189 | end 190 | if trim, 191 | s = strtrim(s); 192 | end -------------------------------------------------------------------------------- /resources/icons/a01.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a01.ico -------------------------------------------------------------------------------- /resources/icons/a02.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a02.ico -------------------------------------------------------------------------------- /resources/icons/a03.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a03.ico -------------------------------------------------------------------------------- /resources/icons/a04.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a04.ico -------------------------------------------------------------------------------- /resources/icons/a05.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a05.ico -------------------------------------------------------------------------------- /resources/icons/a06.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a06.ico -------------------------------------------------------------------------------- /resources/icons/a07.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a07.ico -------------------------------------------------------------------------------- /resources/icons/a08.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a08.ico -------------------------------------------------------------------------------- /resources/icons/a09.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a09.ico -------------------------------------------------------------------------------- /resources/icons/a10.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a10.ico -------------------------------------------------------------------------------- /resources/icons/a11.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a11.ico -------------------------------------------------------------------------------- /resources/icons/a12.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a12.ico -------------------------------------------------------------------------------- /resources/icons/a13.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a13.ico -------------------------------------------------------------------------------- /resources/icons/a14.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a14.ico -------------------------------------------------------------------------------- /resources/icons/a15.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/a15.ico -------------------------------------------------------------------------------- /resources/icons/ardupilotlog.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/ardupilotlog.ico -------------------------------------------------------------------------------- /resources/icons/ardupilotlog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuWeipeng/ArduPilotLog/e21e035163ff9bc65a28ab579cfdbdb7669fe1e6/resources/icons/ardupilotlog.png -------------------------------------------------------------------------------- /src/APLDB.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "APLDB.h" 5 | 6 | APL_LOGGING_CATEGORY(APLDB_LOG, "APLDBLog") 7 | 8 | APLDB *APLDB::_instance; 9 | 10 | APLDB::APLDB() 11 | : _Number(0) 12 | { 13 | _instance = this; 14 | } 15 | 16 | void APLDB::createAPLDB() 17 | { 18 | _apldb = QSqlDatabase::addDatabase("QSQLITE"); 19 | _apldb.setDatabaseName(DB_FILE); 20 | 21 | if(!_apldb.open()){ 22 | qCDebug(APLDB_LOG) << _apldb.lastError(); 23 | qCDebug(APLDB_LOG) << _apldb.drivers(); 24 | }else{ 25 | QSqlQuery query; 26 | _apldb.transaction(); 27 | bool success = query.exec("CREATE TABLE maintable(id INT8 PRIMARY KEY, len INT8, name VARCHAR, format VARCHAR, labels VARCHAR)"); 28 | if(success){ 29 | qCDebug(APLDB_LOG) << "create maintable success"; 30 | }else{ 31 | qCDebug(APLDB_LOG) << "create maintable failed"; 32 | } 33 | } 34 | } 35 | 36 | //true: id already exist 37 | bool APLDB::checkMainTable(quint8 id) 38 | { 39 | QSqlQuery query; 40 | 41 | if(!_apldb.isOpen()){ 42 | qCDebug(APLDB_LOG) << QString(DB_FILE) << " is closed"; 43 | return false; 44 | } 45 | 46 | query.exec(QString("SELECT id FROM maintable WHERE id LIKE %1").arg(id)); 47 | if(!query.next()){ 48 | //qCDebug(APLDB_LOG) << QString("type: %1 don't exist").arg(id); 49 | return false; 50 | } 51 | 52 | return true; 53 | } 54 | 55 | void APLDB::addToMainTable(quint8 type, 56 | quint8 len, 57 | QString name, 58 | QString format, 59 | QString labels) 60 | { 61 | QSqlQuery query_insert; 62 | QSqlQuery query_check; 63 | 64 | query_insert.exec(QString("INSERT INTO maintable VALUES(%1,%2,\"%3\",\"%4\",\"%5\")") 65 | .arg(type).arg(len).arg(name,format,labels)); 66 | 67 | query_check.exec(QString("SELECT COUNT(*) FROM SQLITE_MASTER WHERE TYPE='table' AND name='%1'").arg(name)); 68 | 69 | query_check.next(); 70 | 71 | if(query_check.value(0).toInt()==0){ 72 | if(!_createSubTable(name, format, labels)){ 73 | qCDebug(APLDB_LOG) << name << "Sub table create fail"; 74 | } 75 | }else{ 76 | qCDebug(APLDB_LOG) << "Sub table already exist"; 77 | } 78 | 79 | } 80 | 81 | void APLDB::addToSubTable(QString name, QString values) 82 | { 83 | QSqlQuery query_insert; 84 | 85 | values = QString("%1,%2").arg(++_Number).arg(values); 86 | query_insert.prepare(QString("INSERT INTO %1 VALUES(%2)").arg(name).arg(values)); 87 | if(!query_insert.exec()){ 88 | QSqlError queryErr = query_insert.lastError(); 89 | qCDebug(APLDB_LOG)<<"addToSubTable"<& data, double offset, double scale) 260 | { 261 | QSqlQuery query; 262 | 263 | query.prepare(QString("SELECT %1 FROM %2").arg(field).arg(table)); 264 | 265 | if(!query.exec()){ 266 | QSqlError queryErr = query.lastError(); 267 | qCDebug(APLDB_LOG)< 5 | #include 6 | #include "APLLoggingCategory.h" 7 | 8 | #define DB_FILE "APLDB.db" 9 | 10 | Q_DECLARE_LOGGING_CATEGORY(APLDB_LOG) 11 | 12 | class APLDB : public QObject 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | APLDB(); 18 | 19 | void createAPLDB(); 20 | 21 | //true: id already exist 22 | bool checkMainTable(quint8 id); 23 | 24 | void addToMainTable(quint8 type, 25 | quint8 len, 26 | QString name, 27 | QString format, 28 | QString labels); 29 | 30 | void addToSubTable(QString name, QString values); 31 | 32 | void getFormat(quint8 &id, QString &name, QString &format); 33 | 34 | bool isOpen() const { return _apldb.isOpen(); } 35 | 36 | void close() { _apldb.close(); } 37 | 38 | void commit() { _apldb.commit(); } 39 | 40 | QString getGroupName(int i); 41 | 42 | QString getItemName(QString table, int i); 43 | 44 | int getGroupCount(); 45 | 46 | int getItemCount(QString table); 47 | 48 | int getLen(QString table, QString field); 49 | 50 | bool getData(QString table, QString field, int len, QVector& data, double offset = 0, double scale = 1); 51 | 52 | void getData(QString table, QString field, int index, double& data); 53 | 54 | void deleteDataBase(); 55 | 56 | void reset(); 57 | 58 | bool isEmpty(QString table); 59 | 60 | static APLDB* getAPLDB() { return _instance; } 61 | 62 | private: 63 | static APLDB* _instance; 64 | QSqlDatabase _apldb; 65 | quint32 _Number; 66 | 67 | //true: create sub-table success 68 | bool _createSubTable(QString &name, QString &format, QString &field) const; 69 | 70 | void _createTableField(QString &format, QString &field, QString &table_field) const; 71 | }; 72 | 73 | #endif // APLDB_H 74 | -------------------------------------------------------------------------------- /src/APLQmlWidgetHolder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "APLQmlWidgetHolder.h" 3 | 4 | APLQmlWidgetHolder::APLQmlWidgetHolder(const QString& title, QAction* action, QWidget *parent) : 5 | APLDockWidget(title, action, parent) 6 | { 7 | _ui.setupUi(this); 8 | 9 | layout()->setContentsMargins(0,0,0,0); 10 | 11 | if (action) { 12 | setWindowTitle(title); 13 | } 14 | setResizeMode(QQuickWidget::SizeRootObjectToView); 15 | } 16 | 17 | APLQmlWidgetHolder::~APLQmlWidgetHolder() 18 | { 19 | 20 | } 21 | 22 | void APLQmlWidgetHolder::setSource(const QUrl& qmlUrl) 23 | { 24 | _ui.qmlWidget->setSource(qmlUrl); 25 | } 26 | 27 | void APLQmlWidgetHolder::setContextPropertyObject(const QString& name, QObject* object) 28 | { 29 | _ui.qmlWidget->rootContext()->setContextProperty(name, object); 30 | } 31 | 32 | QQmlContext* APLQmlWidgetHolder::getRootContext(void) 33 | { 34 | return _ui.qmlWidget->rootContext(); 35 | } 36 | 37 | QQuickItem* APLQmlWidgetHolder::getRootObject(void) 38 | { 39 | return _ui.qmlWidget->rootObject(); 40 | } 41 | 42 | QQmlEngine* APLQmlWidgetHolder::getEngine() 43 | { 44 | return _ui.qmlWidget->engine(); 45 | } 46 | 47 | 48 | void APLQmlWidgetHolder::setResizeMode(QQuickWidget::ResizeMode resizeMode) 49 | { 50 | _ui.qmlWidget->setResizeMode(resizeMode); 51 | } 52 | -------------------------------------------------------------------------------- /src/APLQmlWidgetHolder.h: -------------------------------------------------------------------------------- 1 | #ifndef APLQmlWidgetHolder_h 2 | #define APLQmlWidgetHolder_h 3 | 4 | #include 5 | #include 6 | #include 7 | #include "APLDockWidget.h" 8 | #include "ui_APLQmlWidgetHolder.h" 9 | 10 | namespace Ui { 11 | class APLQmlWidgetHolder; 12 | } 13 | 14 | /// This is used to create widgets which are implemented in QML. 15 | 16 | class APLQmlWidgetHolder : public APLDockWidget 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | // This has a title and action since the base class is APLQmlWidget. In order to use this 22 | // control as a normal QWidget, not a doc widget just pass in: 23 | // title = QString() 24 | // action = NULL 25 | explicit APLQmlWidgetHolder(const QString& title, QAction* action, QWidget *parent = 0); 26 | ~APLQmlWidgetHolder(); 27 | 28 | /// Get Root Context 29 | QQmlContext* getRootContext(void); 30 | 31 | /// Get Root Object 32 | QQuickItem* getRootObject(void); 33 | 34 | /// Get QML Engine 35 | QQmlEngine* getEngine(); 36 | 37 | void setSource(const QUrl& qmlUrl); 38 | 39 | void setContextPropertyObject(const QString& name, QObject* object); 40 | 41 | /// Sets the resize mode for the QQuickWidget container 42 | void setResizeMode(QQuickWidget::ResizeMode resizeMode); 43 | 44 | private: 45 | Ui::APLQmlWidgetHolder _ui; 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/APLQmlWidgetHolder.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | APLQmlWidgetHolder 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | QQuickWidget 29 | QWidget 30 |
QtQuickWidgets/QQuickWidget
31 |
32 |
33 | 34 | 35 |
36 | -------------------------------------------------------------------------------- /src/APLRead.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "APLRead.h" 6 | #include "APLDB.h" 7 | #include "mainwindow.h" 8 | 9 | APL_LOGGING_CATEGORY(APLREAD_LOG, "APLReadLog") 10 | 11 | #define NAME_LEN 4 12 | #define FORMAT_LEN 16 13 | #define LABELS_LEN 64 14 | 15 | APLRead* APLRead::_instance; 16 | 17 | static LFMT FMT[256]; // 256 at least 18 | 19 | APLRead::APLRead() 20 | : _apldb(new APLDB) 21 | { 22 | _instance = this; 23 | _resetDataBase(); 24 | } 25 | 26 | APLRead::~APLRead() 27 | { 28 | delete _apldb; 29 | } 30 | 31 | void APLRead::_resetDataBase() 32 | { 33 | for(int i=0; i<256; i++) 34 | _resetFMT(i); 35 | _apldb->deleteDataBase(); 36 | _apldb->createAPLDB(); 37 | _apldb->reset(); 38 | } 39 | 40 | void APLRead::_resetFMT(int i) 41 | { 42 | FMT[i].id = 0; 43 | FMT[i].name = ""; 44 | FMT[i].format = ""; 45 | FMT[i].valid = true; 46 | } 47 | 48 | void APLRead::getFileDir(const QString &file_dir) 49 | { 50 | _file_name = QFileInfo(file_dir).fileName(); 51 | MainWindow::getMainWindow()->setWindowTitle(QString("ArduPilotLog ").append(file_dir)); 52 | _resetDataBase(); 53 | getDatastream(file_dir); 54 | } 55 | 56 | void APLRead::getDatastream(const QString &file_dir) 57 | { 58 | QFile file; 59 | 60 | file.setFileName(file_dir); 61 | if(!file.open(QIODevice::ReadOnly)) 62 | { 63 | qCDebug(APLREAD_LOG)<< "can not open file!"; 64 | return; 65 | } 66 | 67 | QDataStream in(&file); // read the data serialized from the file 68 | _decode(in); 69 | 70 | _apldb->commit(); 71 | emit fileOpened(); 72 | qCDebug(APLREAD_LOG) << "All data have been read"; 73 | 74 | file.close(); 75 | } 76 | 77 | void APLRead::_decode(QDataStream &in) const 78 | { 79 | quint8 head_check[3]; 80 | quint8 currentByte; 81 | quint8 ptr_pos = 0; 82 | 83 | while(!in.atEnd()) 84 | { 85 | in >> currentByte; 86 | 87 | if(ptr_pos<=3){ 88 | ptr_pos++; 89 | } 90 | 91 | if (ptr_pos > 3){ 92 | head_check[0] = head_check[1]; 93 | head_check[1] = head_check[2]; 94 | head_check[2] = currentByte; 95 | }else{ 96 | switch(ptr_pos){ 97 | case 1: 98 | head_check[0] = currentByte; 99 | continue; 100 | case 2: 101 | head_check[1] = currentByte; 102 | continue; 103 | case 3: 104 | head_check[2] = currentByte; 105 | } 106 | } 107 | if (head_check[0]==HEAD_BYTE1 && head_check[1]==HEAD_BYTE2) 108 | { 109 | if(head_check[2] == LOG_FORMAT_MSG){ 110 | quint8 type; 111 | in >> type; 112 | quint8 len; 113 | char name[NAME_LEN+1]; 114 | char format[FORMAT_LEN+1]; 115 | char labels[LABELS_LEN+1]; 116 | QString log_name; 117 | QString log_format; 118 | QString log_labels; 119 | 120 | memset(name,0,sizeof(name)); 121 | memset(format,0,sizeof(format)); 122 | memset(labels,0,sizeof(labels)); 123 | 124 | in >> len; 125 | in.readRawData(name , NAME_LEN ); 126 | in.readRawData(format, FORMAT_LEN); 127 | in.readRawData(labels, LABELS_LEN); 128 | log_name = QString(name); 129 | log_format = QString(format); 130 | log_labels = QString(labels); 131 | 132 | if( _checkMessage(log_name,log_format,log_labels)){ 133 | _apldb->addToMainTable(type, 134 | len, 135 | log_name, 136 | log_format, 137 | log_labels); 138 | } 139 | }else{ 140 | quint8 id = head_check[2]; 141 | if(FMT[id].name.isEmpty() && FMT[id].format.isEmpty() && FMT[id].valid){ 142 | if(_apldb->checkMainTable(id)) 143 | { 144 | _apldb->getFormat(id, FMT[id].name, FMT[id].format); 145 | }else{ 146 | FMT[id].valid = false; 147 | } 148 | } 149 | 150 | if(FMT[id].valid && !FMT[id].format.isEmpty()){ 151 | QString value_str = ""; 152 | _decodeData(FMT[id].format, in, value_str); 153 | _apldb->addToSubTable(FMT[id].name, value_str); 154 | } 155 | } 156 | } 157 | } 158 | } 159 | 160 | void APLRead::_decodeData(QString &format, QDataStream &in, QString &value) const 161 | { 162 | QByteArray formatArray = format.toLatin1(); 163 | 164 | for(qint8 i = 0; i< formatArray.count(); i++){ 165 | switch(formatArray[i]){ 166 | case 'a': //int16_t[32] 167 | qint16 v16_32[32]; 168 | memset(v16_32, 0, sizeof(v16_32)); 169 | in.readRawData((char *)v16_32, sizeof(v16_32)); 170 | for(int i=0; i<32; i++) 171 | if(i == 31) 172 | value = QString ("%1%2,").arg(value).arg(QString(v16_32[i])); 173 | else 174 | value = QString ("%1%2 ").arg(value).arg(QString(v16_32[i])); 175 | break; 176 | case 'b': //int8_t 177 | qint8 v8; 178 | in.readRawData((char *)&v8, 1); 179 | value = QString ("%1%2,").arg(value).arg(v8); 180 | break; 181 | case 'B': //uint8_t 182 | quint8 vu8; 183 | in.readRawData((char *)&vu8, 1); 184 | value = QString ("%1%2,").arg(value).arg(vu8); 185 | break; 186 | case 'h': //int16_t 187 | qint16 v16; 188 | in.readRawData((char *)&v16, 2); 189 | value = QString ("%1%2,").arg(value).arg(v16); 190 | break; 191 | case 'H': //uint16_t 192 | quint16 vu16; 193 | in.readRawData((char *)&vu16, 2); 194 | value = QString ("%1%2,").arg(value).arg(vu16); 195 | break; 196 | case 'i': //int32_t 197 | qint32 v32; 198 | in.readRawData((char *)&v32, 4); 199 | value = QString ("%1%2,").arg(value).arg(v32); 200 | break; 201 | case 'I': //uint32_t 202 | quint32 vu32; 203 | in.readRawData((char *)&vu32, 4); 204 | value = QString ("%1%2,").arg(value).arg(vu32); 205 | break; 206 | case 'f': //float 207 | float vf; 208 | in.readRawData((char *)&vf, 4); 209 | if(qIsNaN(vf) || qIsInf(vf)) vf = 0.0f; 210 | value = QString ("%1%2,").arg(value).arg(vf); 211 | break; 212 | case 'd': //double 213 | double vd; 214 | in.readRawData((char *)&vd, 8); 215 | value = QString ("%1%2,").arg(value).arg(vd); 216 | break; 217 | case 'n': //char[4] 218 | char vc_4[4+1]; 219 | memset(vc_4, 0, sizeof(vc_4)); 220 | in.readRawData(vc_4, sizeof(char)*4); 221 | value = QString ("%1\"%2\",").arg(value).arg(QString(QByteArray(vc_4))); 222 | break; 223 | case 'N': //char[16] 224 | char vc_16[16+1]; 225 | memset(vc_16, 0, sizeof(vc_16)); 226 | in.readRawData(vc_16, sizeof(char)*16); 227 | value = QString ("%1\"%2\",").arg(value).arg(QString(QByteArray(vc_16))); 228 | break; 229 | case 'Z': //char[64] 230 | char vc_64[64+1]; 231 | memset(vc_64, 0, sizeof(vc_64)); 232 | in.readRawData(vc_64, sizeof(char)*64); 233 | value = QString ("%1\"%2\",").arg(value).arg(QString(QByteArray(vc_64))); 234 | break; 235 | case 'c': //int16_t * 100 236 | qint16 v16x100; 237 | in.readRawData((char *)&v16x100, 2); 238 | value = QString ("%1%2,").arg(value).arg((double)(v16x100/100.0f)); 239 | break; 240 | case 'C': //uint16_t * 100 241 | quint16 vu16x100; 242 | in.readRawData((char *)&vu16x100, 2); 243 | value = QString ("%1%2,").arg(value).arg((double)(vu16x100/100.0f)); 244 | break; 245 | case 'e': //int32_t * 100 246 | qint32 v32x100; 247 | in.readRawData((char *)&v32x100, 4); 248 | value = QString ("%1%2,").arg(value).arg((double)(v32x100/100.0f)); 249 | break; 250 | case 'E': //uint32_t * 100 251 | quint32 vu32x100; 252 | in.readRawData((char *)&vu32x100, 4); 253 | value = QString ("%1%2,").arg(value).arg((double)(vu32x100/100.0f)); 254 | break; 255 | case 'L': //int32_t latitude/longitude 256 | qint32 v32l; 257 | in.readRawData((char *)&v32l, 4); 258 | value = QString ("%1%2,").arg(value).arg(v32l); 259 | break; 260 | case 'M': //uint8_t flight mode 261 | quint8 vu8m; 262 | in.readRawData((char *)&vu8m, 1); 263 | value = QString ("%1%2,").arg(value).arg(vu8m); 264 | break; 265 | case 'q': //int64_t 266 | qint64 v64; 267 | in.readRawData((char *)&v64, 8); 268 | value = QString ("%1%2,").arg(value).arg(v64); 269 | break; 270 | case 'Q': //uint64_t 271 | quint64 vu64; 272 | in.readRawData((char *)&vu64, 8); 273 | value = QString ("%1%2,").arg(value).arg(vu64); 274 | break; 275 | } 276 | } 277 | value.chop(1); 278 | 279 | } 280 | bool APLRead::_checkMessage(QString &name, QString &format, QString &labels) const 281 | { 282 | return _checkName(name) && _checkFormat(format) && _checkLabels(labels); 283 | } 284 | 285 | bool APLRead::_checkName(QString &name) const 286 | { 287 | QRegExp reg("^[A-Z0-9]{1,4}$"); 288 | QRegExpValidator validator(reg,0); 289 | 290 | int pos = 0; 291 | if(QValidator::Acceptable!=validator.validate(name,pos)){ 292 | return false; 293 | } 294 | 295 | return true; 296 | } 297 | 298 | bool APLRead::_checkFormat(QString &format) const 299 | { 300 | QRegExp reg("^[A-Za-z]{1,16}$"); 301 | QRegExpValidator validator(reg,0); 302 | 303 | int pos = 0; 304 | if(QValidator::Acceptable!=validator.validate(format,pos)){ 305 | return false; 306 | } 307 | 308 | return true; 309 | } 310 | 311 | bool APLRead::_checkLabels(QString &labels) const 312 | { 313 | QRegExp reg("^[A-Za-z0-9,]{1,64}$"); 314 | QRegExpValidator validator(reg,0); 315 | 316 | int pos = 0; 317 | if(QValidator::Acceptable!=validator.validate(labels,pos)){ 318 | return false; 319 | } 320 | 321 | int index_of_Primary = labels.indexOf("Primary", Qt::CaseInsensitive); 322 | if( index_of_Primary != -1 ) { 323 | labels.insert(index_of_Primary+7, QString('\'')); 324 | labels.insert(index_of_Primary, '\''); 325 | qCDebug(APLREAD_LOG) < 2 | #include 3 | #include 4 | #include 5 | #include "APLReadConf.h" 6 | #include "mainwindow.h" 7 | 8 | APL_LOGGING_CATEGORY(APLREAD_CONF_LOG, "APLReadConfLog") 9 | 10 | APLReadConf::APLReadConf() 11 | { 12 | } 13 | 14 | APLReadConf::~APLReadConf() 15 | { 16 | } 17 | 18 | void APLReadConf::getFileDir(const QString &file_dir) 19 | { 20 | _file_name = QFileInfo(file_dir).fileName(); 21 | getDatastream(file_dir); 22 | 23 | qCDebug(APLREAD_CONF_LOG) << file_dir; 24 | } 25 | 26 | void APLReadConf::getDatastream(const QString &file_dir) 27 | { 28 | QFile file; 29 | 30 | file.setFileName(file_dir); 31 | if(!file.open(QIODevice::ReadOnly)) 32 | { 33 | qCDebug(APLREAD_CONF_LOG)<< "can not open file!"; 34 | return; 35 | } 36 | 37 | QTextStream in(&file); 38 | _decode(in); 39 | 40 | emit fileOpened(); 41 | qCDebug(APLREAD_CONF_LOG) << "All plot config have been read"; 42 | 43 | file.close(); 44 | } 45 | 46 | void APLReadConf::_decode(QTextStream &in) const 47 | { 48 | QStringList conf; 49 | QString lineStr; 50 | while(!in.atEnd()) 51 | { 52 | lineStr = in.readLine(); 53 | 54 | if(lineStr.left(1).compare("#") == 0) continue; 55 | 56 | if(!lineStr.isEmpty()){ 57 | conf.append(lineStr); 58 | } 59 | } 60 | 61 | MainWindow::getMainWindow()->set_conf(conf); 62 | } 63 | -------------------------------------------------------------------------------- /src/APLReadConf.h: -------------------------------------------------------------------------------- 1 | #ifndef APLREADCONF_H 2 | #define APLREADCONF_H 3 | 4 | #include "APLLoggingCategory.h" 5 | 6 | Q_DECLARE_LOGGING_CATEGORY(APLREAD_CONF_LOG) 7 | 8 | class APLReadConf : public QObject 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | APLReadConf(); 14 | ~APLReadConf(); 15 | 16 | void getDatastream(const QString &file_dir); 17 | QString getFileName(void) { return _file_name; } 18 | 19 | signals: 20 | void fileOpened(); 21 | 22 | public slots: 23 | void getFileDir(const QString &file_dir); 24 | 25 | private: 26 | void _decode(QTextStream &in) const; 27 | 28 | QString _file_name; 29 | }; 30 | 31 | #endif // APLREADCONF_H 32 | -------------------------------------------------------------------------------- /src/AutoResize.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Item { 4 | id:globalResize 5 | property var targetItem: parent 6 | property bool fixedAspectRatio: false // Else zoom from width and height 7 | property bool accordingToX: true // Else according to center 8 | property bool fontAccordingToMax: false 9 | property bool ifAutoResize: true 10 | property string ingnoreAll: "ingnoreAll" 11 | property string ingnoreChildren: "ingnoreChildren" 12 | //变换比例 13 | property real horizontalRatio: 1.0 14 | property real verticalRatio: 1.0 15 | property real fontRatio: 1.0 16 | 17 | property var targetItemGeometry 18 | property var childrenItemGeometry 19 | property var childrenText 20 | property real fontSizeScaleFactor: 1.0 21 | property bool isBegin: false 22 | signal resized() 23 | function begin() { 24 | var _childrenItemGeometry=new Array; 25 | targetItemGeometry = new Object; 26 | targetItemGeometry["width"] = targetItem.width; 27 | targetItemGeometry["height"] = targetItem.height; 28 | var children = targetItem.children; 29 | for(var index = 1; index < children.length; index++) 30 | { 31 | var currentItem = children[index]; 32 | var buf = new Object; 33 | 34 | buf["item"] = currentItem; 35 | buf["name"]=currentItem.objectName; 36 | buf["x"] = currentItem.x; 37 | buf["y"] = currentItem.y; 38 | buf["centerX"] = currentItem.x + (currentItem.width / 2); 39 | buf["centerY"] = currentItem.y + (currentItem.height / 2); 40 | buf["width"] = currentItem.width; 41 | buf["height"] = currentItem.height; 42 | 43 | //to salce the font size 44 | buf["fontSize"]=0; 45 | if(currentItem.font!=undefined) 46 | { 47 | buf["fontSize"]=currentItem.font.pointSize 48 | } 49 | //跳过当前对象以及所有子对象 50 | if(buf["name"]==ingnoreAll) 51 | { 52 | continue; 53 | } 54 | //跳过当前对象的子对象 55 | else if(buf["name"]==ingnoreChildren) 56 | { 57 | _childrenItemGeometry.push(buf) 58 | } 59 | else 60 | { 61 | _childrenItemGeometry.push(buf) 62 | getAllChildren(_childrenItemGeometry,currentItem) 63 | } 64 | } 65 | childrenItemGeometry=_childrenItemGeometry 66 | //console.log("length->"+_childrenItemGeometry.length) 67 | isBegin = true; 68 | } 69 | function getAllChildren(_childrenItemGeometry,target) 70 | { 71 | var children = target.children; 72 | for(var index = 0; index < children.length; index++) 73 | { 74 | var currentItem = children[index]; 75 | var buf = new Object; 76 | 77 | buf["item"] = currentItem; 78 | buf["name"]=currentItem.objectName; 79 | buf["x"] = currentItem.x; 80 | buf["y"] = currentItem.y; 81 | buf["centerX"] = currentItem.x + (currentItem.width / 2); 82 | buf["centerY"] = currentItem.y + (currentItem.height / 2); 83 | buf["width"] = currentItem.width; 84 | buf["height"] = currentItem.height; 85 | buf["fontSize"]=0; 86 | if(currentItem.font!=undefined) 87 | { 88 | buf["fontSize"]=currentItem.font.pointSize 89 | } 90 | //跳过当前对象以及所有子对象 91 | if(buf["name"]=="ingnoreAll") 92 | { 93 | continue; 94 | } 95 | //跳过当前对象的子对象 96 | else if(buf["name"]=="ingnoreChildren") 97 | { 98 | _childrenItemGeometry.push(buf) 99 | } 100 | else 101 | { 102 | _childrenItemGeometry.push(buf) 103 | getAllChildren(_childrenItemGeometry,currentItem) 104 | } 105 | } 106 | } 107 | 108 | function resize() { 109 | if(isBegin&&ifAutoResize) 110 | { 111 | //var horizontalRatio, verticalRatio,fontRatio; 112 | 113 | horizontalRatio = targetItem.width / targetItemGeometry["width"]; 114 | verticalRatio = targetItem.height / targetItemGeometry["height"]; 115 | fontRatio=horizontalRatio>verticalRatio?verticalRatio:horizontalRatio; 116 | //set fontRatio the greatest radio 117 | if(fontAccordingToMax) 118 | fontRatio=(horizontalCenter+verticalRatio)-fontRatio 119 | //console.log("radio->"+horizontalRatio+"--"+verticalRatio) 120 | //console.log("toal item ->"+childrenItemGeometry.length) 121 | for(var index = 0; index < childrenItemGeometry.length; index++) 122 | { 123 | var currentItem=childrenItemGeometry[index] 124 | if(fixedAspectRatio) 125 | { 126 | if(horizontalRatio > verticalRatio) 127 | { 128 | childrenItemGeometry[index]["item"].width = childrenItemGeometry[index]["width"] * verticalRatio; 129 | childrenItemGeometry[index]["item"].height = childrenItemGeometry[index]["height"] * verticalRatio; 130 | } 131 | else 132 | { 133 | childrenItemGeometry[index]["item"].width = childrenItemGeometry[index]["width"] * horizontalRatio; 134 | childrenItemGeometry[index]["item"].height = childrenItemGeometry[index]["height"] * horizontalRatio; 135 | } 136 | } 137 | else 138 | { 139 | childrenItemGeometry[index]["item"].width = childrenItemGeometry[index]["width"] * horizontalRatio; 140 | childrenItemGeometry[index]["item"].height = childrenItemGeometry[index]["height"] * verticalRatio; 141 | } 142 | if(accordingToX) 143 | { 144 | childrenItemGeometry[index]["item"].x = childrenItemGeometry[index]["x"] * horizontalRatio; 145 | childrenItemGeometry[index]["item"].y = childrenItemGeometry[index]["y"] * verticalRatio; 146 | } 147 | else 148 | { 149 | childrenItemGeometry[index]["item"].x = childrenItemGeometry[index]["centerX"] * horizontalRatio - (childrenItemGeometry[index]["item"].width / 2); 150 | childrenItemGeometry[index]["item"].y = childrenItemGeometry[index]["centerY"] * verticalRatio - (childrenItemGeometry[index]["item"].height / 2); 151 | } 152 | if(childrenItemGeometry[index]["item"].font!=undefined) 153 | { 154 | childrenItemGeometry[index]["item"].font.pointSize = childrenItemGeometry[index]["fontSize"]*fontRatio*fontSizeScaleFactor 155 | } 156 | } 157 | globalResize.resized(); 158 | 159 | } 160 | } 161 | 162 | Component.onCompleted: { 163 | begin(); 164 | } 165 | 166 | Component { 167 | id: connections 168 | 169 | Connections { 170 | target: targetItem 171 | 172 | onWidthChanged: { 173 | resize(); 174 | } 175 | onHeightChanged: 176 | { 177 | resize(); 178 | } 179 | } 180 | } 181 | 182 | Loader { 183 | Component.onCompleted: { 184 | sourceComponent = connections; 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/DataAnalyze.h: -------------------------------------------------------------------------------- 1 | #ifndef DATAANALYZE_H 2 | #define DATAANALYZE_H 3 | 4 | #include "APLQmlWidgetHolder.h" 5 | 6 | class DataAnalyze : public APLQmlWidgetHolder 7 | { 8 | public: 9 | DataAnalyze(const QString& title, QAction* action, QWidget *parent = 0) 10 | :APLQmlWidgetHolder(title, action, parent) 11 | { 12 | Q_UNUSED(title); 13 | Q_UNUSED(action); 14 | int screenWidth=QApplication::desktop()->width(); 15 | int screenHeight=QApplication::desktop()->height(); 16 | this->resize(screenWidth/2, screenHeight/3); 17 | setSource(QUrl::fromUserInput("qrc:/qml/DataAnalyze.qml")); 18 | } 19 | }; 20 | 21 | #endif // DATAANALYZE_H 22 | -------------------------------------------------------------------------------- /src/DataAnalyzeController.cpp: -------------------------------------------------------------------------------- 1 | #include "DataAnalyzeController.h" 2 | #include "mainwindow.h" 3 | #include "APLDB.h" 4 | #include "APLRead.h" 5 | 6 | APL_LOGGING_CATEGORY(DATA_ANALYZE_LOG, "DataAnalyzeLog") 7 | 8 | #define LINE_LIST_INIT "Normal"<<"Line1"<<"Line2"<<"Line3"<<"Dot1"<<"Dot2"<<"Dot3"<<"Mark1"<<"Mark2"<<"Mark3" 9 | #define COLOR_LIST_INIT "Red"<<"Green"<<"Blue"<<"Purple"<<"Brown"<<"Pink"<<"DeepSkyBlue"<<"Orange"<<"DarkCyan"<<"Gold" 10 | 11 | DataAnalyzeController::DataAnalyzeController() 12 | { 13 | connect(MainWindow::getMainWindow(), &MainWindow::treeWidgetAddItem, this, &DataAnalyzeController::_setTableList); 14 | connect(APLRead::getAPLRead(), &APLRead::fileOpened, this, &DataAnalyzeController::init); 15 | connect(this, &DataAnalyzeController::plotGraph, MainWindow::getMainWindow(), &MainWindow::plotGraph); 16 | connect(this, &DataAnalyzeController::clearGraph, MainWindow::getMainWindow(), &MainWindow::clearGraphNotTree); 17 | connect(this, &DataAnalyzeController::clear_alreadyPloted, MainWindow::getMainWindow(), &MainWindow::clear_alreadyPloted); 18 | 19 | QList list; 20 | MainWindow::getMainWindow()->ui().splitter->setSizes(list<<0<<1); 21 | 22 | init(); 23 | } 24 | 25 | void DataAnalyzeController::init() 26 | { 27 | _tableList.clear(); 28 | MainWindow::getMainWindow()->requestTableList(); 29 | 30 | _lineList.clear(); 31 | _colorList.clear(); 32 | _lineList << LINE_LIST_INIT; 33 | _colorList << COLOR_LIST_INIT; 34 | _available_colorList = _colorList; 35 | 36 | for(int i=0; i<10; i++){ 37 | _fieldList[i].clear(); 38 | } 39 | 40 | for(int i=0; i0){ 94 | for(int i=0; i<2; i++){ 95 | _tableList1.swap(0, _tableList1.length()-1); 96 | emit tableList1Changed(); 97 | } 98 | } 99 | } 100 | 101 | void DataAnalyzeController::_setTableList(QString table) 102 | { 103 | MainWindow::getMainWindow()->setComboboxList(table); 104 | if (!_tableList.contains(table)){ 105 | _tableList<ui().customPlot; 241 | QList list; 242 | 243 | MainWindow::getMainWindow()->ui().splitter->setSizes(list<<0<<1); 244 | 245 | emit clearGraph(); 246 | 247 | emit clear_alreadyPloted(); 248 | 249 | _update_colorList(); 250 | 251 | for(int i=0; ireplot(); 265 | } 266 | 267 | 268 | 269 | // Row 1 270 | void 271 | DataAnalyzeController::setFieldList1(QString table) 272 | { 273 | tables[0] = table; 274 | 275 | QList itemList = MainWindow::getMainWindow()->ui().treeWidget->findItems(table, Qt::MatchCaseSensitive); 276 | for(int i=0; ichildCount(); j++){ 280 | _fieldList[0]<child(j)->text(0); 281 | } 282 | emit fieldList1Changed(); 283 | } 284 | _update_hide_tables(table); 285 | } 286 | 287 | void 288 | DataAnalyzeController::setField1(QString field){ 289 | fields[0] = field; 290 | if(field.compare("TimeUS") != 0) setVisible1(true); 291 | _plot(); 292 | } 293 | 294 | void 295 | DataAnalyzeController::setScale1(QString scale){ 296 | if(!_isNumber(scale)) return; 297 | 298 | _scale[0] = scale.left(scale.length()).toFloat(); 299 | _scale[0] = QString::number(_scale[0], 'f', 3).toFloat(); 300 | emit scale1Changed(); 301 | 302 | _plot(); 303 | } 304 | 305 | void 306 | DataAnalyzeController::setOffsetX1(QString offset){ 307 | if(!_isNumber(offset)) return; 308 | 309 | _offsetX[0] = (int)offset.left(offset.length()).toFloat(); 310 | emit offsetX1Changed(); 311 | 312 | _plot(); 313 | } 314 | 315 | void 316 | DataAnalyzeController::setOffsetY1(QString offset){ 317 | if(!_isNumber(offset)) return; 318 | 319 | _offsetY[0] = offset.left(offset.length()).toFloat(); 320 | _offsetY[0] = QString::number(_offsetY[0], 'f', 2).toFloat(); 321 | emit offsetY1Changed(); 322 | 323 | _plot(); 324 | } 325 | 326 | void 327 | DataAnalyzeController::setVisible1(bool visible){ 328 | _visible[0] = visible; 329 | emit visible1Changed(); 330 | 331 | _plot(); 332 | } 333 | 334 | void 335 | DataAnalyzeController::setLineStyle1(int style){ 336 | _style[0] = style; 337 | 338 | _plot(); 339 | } 340 | 341 | void 342 | DataAnalyzeController::setLineColor1(QString color){ 343 | _color[0] = _colorList.indexOf(color); 344 | 345 | _plot(); 346 | } 347 | 348 | // Row 2 349 | void 350 | DataAnalyzeController::setFieldList2(QString table) 351 | { 352 | tables[1] = table; 353 | 354 | QList itemList = MainWindow::getMainWindow()->ui().treeWidget->findItems(table, Qt::MatchCaseSensitive); 355 | for(int i=0; ichildCount(); j++){ 359 | _fieldList[1]<child(j)->text(0); 360 | } 361 | emit fieldList2Changed(); 362 | } 363 | _update_hide_tables(table); 364 | } 365 | 366 | void 367 | DataAnalyzeController::setField2(QString field){ 368 | fields[1] = field; 369 | if(field.compare("TimeUS") != 0) setVisible2(true); 370 | _plot(); 371 | } 372 | 373 | void 374 | DataAnalyzeController::setScale2(QString scale){ 375 | if(!_isNumber(scale)) return; 376 | 377 | _scale[1] = scale.left(scale.length()).toFloat(); 378 | _scale[1] = QString::number(_scale[1], 'f', 3).toFloat(); 379 | emit scale2Changed(); 380 | 381 | _plot(); 382 | } 383 | 384 | void 385 | DataAnalyzeController::setOffsetX2(QString offset){ 386 | if(!_isNumber(offset)) return; 387 | 388 | _offsetX[1] = (int)offset.left(offset.length()).toFloat(); 389 | emit offsetX2Changed(); 390 | 391 | _plot(); 392 | } 393 | 394 | void 395 | DataAnalyzeController::setOffsetY2(QString offset){ 396 | if(!_isNumber(offset)) return; 397 | 398 | _offsetY[1] = offset.left(offset.length()).toFloat(); 399 | _offsetY[1] = QString::number(_offsetY[1], 'f', 2).toFloat(); 400 | emit offsetY2Changed(); 401 | 402 | _plot(); 403 | } 404 | 405 | void 406 | DataAnalyzeController::setVisible2(bool visible){ 407 | _visible[1] = visible; 408 | emit visible2Changed(); 409 | 410 | _plot(); 411 | } 412 | 413 | void 414 | DataAnalyzeController::setLineStyle2(int style){ 415 | _style[1] = style; 416 | 417 | _plot(); 418 | } 419 | 420 | void 421 | DataAnalyzeController::setLineColor2(QString color){ 422 | _color[1] = _colorList.indexOf(color); 423 | 424 | _plot(); 425 | } 426 | 427 | // Row 3 428 | void 429 | DataAnalyzeController::setFieldList3(QString table) 430 | { 431 | tables[2] = table; 432 | 433 | QList itemList = MainWindow::getMainWindow()->ui().treeWidget->findItems(table, Qt::MatchCaseSensitive); 434 | for(int i=0; ichildCount(); j++){ 438 | _fieldList[2]<child(j)->text(0); 439 | } 440 | emit fieldList3Changed(); 441 | } 442 | _update_hide_tables(table); 443 | } 444 | 445 | void 446 | DataAnalyzeController::setField3(QString field){ 447 | fields[2] = field; 448 | if(field.compare("TimeUS") != 0) setVisible3(true); 449 | _plot(); 450 | } 451 | 452 | void 453 | DataAnalyzeController::setScale3(QString scale){ 454 | if(!_isNumber(scale)) return; 455 | 456 | _scale[2] = scale.left(scale.length()).toFloat(); 457 | _scale[2] = QString::number(_scale[2], 'f', 3).toFloat(); 458 | emit scale3Changed(); 459 | 460 | _plot(); 461 | } 462 | 463 | void 464 | DataAnalyzeController::setOffsetX3(QString offset){ 465 | if(!_isNumber(offset)) return; 466 | 467 | _offsetX[2] = (int)offset.left(offset.length()).toFloat(); 468 | emit offsetX3Changed(); 469 | 470 | _plot(); 471 | } 472 | 473 | void 474 | DataAnalyzeController::setOffsetY3(QString offset){ 475 | if(!_isNumber(offset)) return; 476 | 477 | _offsetY[2] = offset.left(offset.length()).toFloat(); 478 | _offsetY[2] = QString::number(_offsetY[2], 'f', 2).toFloat(); 479 | emit offsetY3Changed(); 480 | 481 | _plot(); 482 | } 483 | 484 | void 485 | DataAnalyzeController::setVisible3(bool visible){ 486 | _visible[2] = visible; 487 | emit visible3Changed(); 488 | 489 | _plot(); 490 | } 491 | 492 | void 493 | DataAnalyzeController::setLineStyle3(int style){ 494 | _style[2] = style; 495 | 496 | _plot(); 497 | } 498 | 499 | void 500 | DataAnalyzeController::setLineColor3(QString color){ 501 | _color[2] = _colorList.indexOf(color); 502 | 503 | _plot(); 504 | } 505 | 506 | // Row 4 507 | void 508 | DataAnalyzeController::setFieldList4(QString table) 509 | { 510 | tables[3] = table; 511 | 512 | QList itemList = MainWindow::getMainWindow()->ui().treeWidget->findItems(table, Qt::MatchCaseSensitive); 513 | for(int i=0; ichildCount(); j++){ 517 | _fieldList[3]<child(j)->text(0); 518 | } 519 | emit fieldList4Changed(); 520 | } 521 | _update_hide_tables(table); 522 | } 523 | 524 | void 525 | DataAnalyzeController::setField4(QString field){ 526 | fields[3] = field; 527 | if(field.compare("TimeUS") != 0) setVisible4(true); 528 | _plot(); 529 | } 530 | 531 | void 532 | DataAnalyzeController::setScale4(QString scale){ 533 | if(!_isNumber(scale)) return; 534 | 535 | _scale[3] = scale.left(scale.length()).toFloat(); 536 | _scale[3] = QString::number(_scale[3], 'f', 3).toFloat(); 537 | emit scale4Changed(); 538 | 539 | _plot(); 540 | } 541 | 542 | void 543 | DataAnalyzeController::setOffsetX4(QString offset){ 544 | if(!_isNumber(offset)) return; 545 | 546 | _offsetX[3] = (int)offset.left(offset.length()).toFloat(); 547 | emit offsetX4Changed(); 548 | 549 | _plot(); 550 | } 551 | 552 | void 553 | DataAnalyzeController::setOffsetY4(QString offset){ 554 | if(!_isNumber(offset)) return; 555 | 556 | _offsetY[3] = offset.left(offset.length()).toFloat(); 557 | _offsetY[3] = QString::number(_offsetY[3], 'f', 2).toFloat(); 558 | emit offsetY4Changed(); 559 | 560 | _plot(); 561 | } 562 | 563 | void 564 | DataAnalyzeController::setVisible4(bool visible){ 565 | _visible[3] = visible; 566 | emit visible4Changed(); 567 | 568 | _plot(); 569 | } 570 | 571 | void 572 | DataAnalyzeController::setLineStyle4(int style){ 573 | _style[3] = style; 574 | 575 | _plot(); 576 | } 577 | 578 | void 579 | DataAnalyzeController::setLineColor4(QString color){ 580 | _color[3] = _colorList.indexOf(color); 581 | 582 | _plot(); 583 | } 584 | 585 | // Row 5 586 | void 587 | DataAnalyzeController::setFieldList5(QString table) 588 | { 589 | tables[4] = table; 590 | 591 | QList itemList = MainWindow::getMainWindow()->ui().treeWidget->findItems(table, Qt::MatchCaseSensitive); 592 | for(int i=0; ichildCount(); j++){ 596 | _fieldList[4]<child(j)->text(0); 597 | } 598 | emit fieldList5Changed(); 599 | } 600 | _update_hide_tables(table); 601 | } 602 | 603 | void 604 | DataAnalyzeController::setField5(QString field){ 605 | fields[4] = field; 606 | if(field.compare("TimeUS") != 0) setVisible5(true); 607 | _plot(); 608 | } 609 | 610 | void 611 | DataAnalyzeController::setScale5(QString scale){ 612 | if(!_isNumber(scale)) return; 613 | 614 | _scale[4] = scale.left(scale.length()).toFloat(); 615 | _scale[4] = QString::number(_scale[4], 'f', 3).toFloat(); 616 | emit scale5Changed(); 617 | 618 | _plot(); 619 | } 620 | 621 | void 622 | DataAnalyzeController::setOffsetX5(QString offset){ 623 | if(!_isNumber(offset)) return; 624 | 625 | _offsetX[4] = (int)offset.left(offset.length()).toFloat(); 626 | emit offsetX5Changed(); 627 | 628 | _plot(); 629 | } 630 | 631 | void 632 | DataAnalyzeController::setOffsetY5(QString offset){ 633 | if(!_isNumber(offset)) return; 634 | 635 | _offsetY[4] = offset.left(offset.length()).toFloat(); 636 | _offsetY[4] = QString::number(_offsetY[4], 'f', 2).toFloat(); 637 | emit offsetY5Changed(); 638 | 639 | _plot(); 640 | } 641 | 642 | void 643 | DataAnalyzeController::setVisible5(bool visible){ 644 | _visible[4] = visible; 645 | emit visible5Changed(); 646 | 647 | _plot(); 648 | } 649 | 650 | void 651 | DataAnalyzeController::setLineStyle5(int style){ 652 | _style[4] = style; 653 | 654 | _plot(); 655 | } 656 | 657 | void 658 | DataAnalyzeController::setLineColor5(QString color){ 659 | _color[4] = _colorList.indexOf(color); 660 | 661 | _plot(); 662 | } 663 | 664 | // Row 6 665 | void 666 | DataAnalyzeController::setFieldList6(QString table) 667 | { 668 | tables[5] = table; 669 | 670 | QList itemList = MainWindow::getMainWindow()->ui().treeWidget->findItems(table, Qt::MatchCaseSensitive); 671 | for(int i=0; ichildCount(); j++){ 675 | _fieldList[5]<child(j)->text(0); 676 | } 677 | emit fieldList6Changed(); 678 | } 679 | _update_hide_tables(table); 680 | } 681 | 682 | void 683 | DataAnalyzeController::setField6(QString field){ 684 | fields[5] = field; 685 | if(field.compare("TimeUS") != 0) setVisible6(true); 686 | _plot(); 687 | } 688 | 689 | void 690 | DataAnalyzeController::setScale6(QString scale){ 691 | if(!_isNumber(scale)) return; 692 | 693 | _scale[5] = scale.left(scale.length()).toFloat(); 694 | _scale[5] = QString::number(_scale[5], 'f', 3).toFloat(); 695 | emit scale6Changed(); 696 | 697 | _plot(); 698 | } 699 | 700 | void 701 | DataAnalyzeController::setOffsetX6(QString offset){ 702 | if(!_isNumber(offset)) return; 703 | 704 | _offsetX[5] = (int)offset.left(offset.length()).toFloat(); 705 | emit offsetX6Changed(); 706 | 707 | _plot(); 708 | } 709 | 710 | void 711 | DataAnalyzeController::setOffsetY6(QString offset){ 712 | if(!_isNumber(offset)) return; 713 | 714 | _offsetY[5] = offset.left(offset.length()).toFloat(); 715 | _offsetY[5] = QString::number(_offsetY[5], 'f', 2).toFloat(); 716 | emit offsetY6Changed(); 717 | 718 | _plot(); 719 | } 720 | 721 | void 722 | DataAnalyzeController::setVisible6(bool visible){ 723 | _visible[5] = visible; 724 | emit visible6Changed(); 725 | 726 | _plot(); 727 | } 728 | 729 | void 730 | DataAnalyzeController::setLineStyle6(int style){ 731 | _style[5] = style; 732 | 733 | _plot(); 734 | } 735 | 736 | void 737 | DataAnalyzeController::setLineColor6(QString color){ 738 | _color[5] = _colorList.indexOf(color); 739 | 740 | _plot(); 741 | } 742 | 743 | // Row 7 744 | void 745 | DataAnalyzeController::setFieldList7(QString table) 746 | { 747 | tables[6] = table; 748 | 749 | QList itemList = MainWindow::getMainWindow()->ui().treeWidget->findItems(table, Qt::MatchCaseSensitive); 750 | for(int i=0; ichildCount(); j++){ 754 | _fieldList[6]<child(j)->text(0); 755 | } 756 | emit fieldList7Changed(); 757 | } 758 | _update_hide_tables(table); 759 | } 760 | 761 | void 762 | DataAnalyzeController::setField7(QString field){ 763 | fields[6] = field; 764 | if(field.compare("TimeUS") != 0) setVisible7(true); 765 | _plot(); 766 | } 767 | 768 | void 769 | DataAnalyzeController::setScale7(QString scale){ 770 | if(!_isNumber(scale)) return; 771 | 772 | _scale[6] = scale.left(scale.length()).toFloat(); 773 | _scale[6] = QString::number(_scale[6], 'f', 3).toFloat(); 774 | emit scale7Changed(); 775 | 776 | _plot(); 777 | } 778 | 779 | void 780 | DataAnalyzeController::setOffsetX7(QString offset){ 781 | if(!_isNumber(offset)) return; 782 | 783 | _offsetX[6] = (int)offset.left(offset.length()).toFloat(); 784 | emit offsetX7Changed(); 785 | 786 | _plot(); 787 | } 788 | 789 | void 790 | DataAnalyzeController::setOffsetY7(QString offset){ 791 | if(!_isNumber(offset)) return; 792 | 793 | _offsetY[6] = offset.left(offset.length()).toFloat(); 794 | _offsetY[6] = QString::number(_offsetY[6], 'f', 2).toFloat(); 795 | emit offsetY7Changed(); 796 | 797 | _plot(); 798 | } 799 | 800 | void 801 | DataAnalyzeController::setVisible7(bool visible){ 802 | _visible[6] = visible; 803 | emit visible7Changed(); 804 | 805 | _plot(); 806 | } 807 | 808 | void 809 | DataAnalyzeController::setLineStyle7(int style){ 810 | _style[6] = style; 811 | 812 | _plot(); 813 | } 814 | 815 | void 816 | DataAnalyzeController::setLineColor7(QString color){ 817 | _color[6] = _colorList.indexOf(color); 818 | 819 | _plot(); 820 | } 821 | 822 | // Row 8 823 | void 824 | DataAnalyzeController::setFieldList8(QString table) 825 | { 826 | tables[7] = table; 827 | 828 | QList itemList = MainWindow::getMainWindow()->ui().treeWidget->findItems(table, Qt::MatchCaseSensitive); 829 | for(int i=0; ichildCount(); j++){ 833 | _fieldList[7]<child(j)->text(0); 834 | } 835 | emit fieldList8Changed(); 836 | } 837 | _update_hide_tables(table); 838 | } 839 | 840 | void 841 | DataAnalyzeController::setField8(QString field){ 842 | fields[7] = field; 843 | if(field.compare("TimeUS") != 0) setVisible8(true); 844 | _plot(); 845 | } 846 | 847 | void 848 | DataAnalyzeController::setScale8(QString scale){ 849 | if(!_isNumber(scale)) return; 850 | 851 | _scale[7] = scale.left(scale.length()).toFloat(); 852 | _scale[7] = QString::number(_scale[7], 'f', 3).toFloat(); 853 | emit scale8Changed(); 854 | 855 | _plot(); 856 | } 857 | 858 | void 859 | DataAnalyzeController::setOffsetX8(QString offset){ 860 | if(!_isNumber(offset)) return; 861 | 862 | _offsetX[7] = (int)offset.left(offset.length()).toFloat(); 863 | emit offsetX8Changed(); 864 | 865 | _plot(); 866 | } 867 | 868 | void 869 | DataAnalyzeController::setOffsetY8(QString offset){ 870 | if(!_isNumber(offset)) return; 871 | 872 | _offsetY[7] = offset.left(offset.length()).toFloat(); 873 | _offsetY[7] = QString::number(_offsetY[7], 'f', 2).toFloat(); 874 | emit offsetY8Changed(); 875 | 876 | _plot(); 877 | } 878 | 879 | void 880 | DataAnalyzeController::setVisible8(bool visible){ 881 | _visible[7] = visible; 882 | emit visible8Changed(); 883 | 884 | _plot(); 885 | } 886 | 887 | void 888 | DataAnalyzeController::setLineStyle8(int style){ 889 | _style[7] = style; 890 | 891 | _plot(); 892 | } 893 | 894 | void 895 | DataAnalyzeController::setLineColor8(QString color){ 896 | _color[7] = _colorList.indexOf(color); 897 | 898 | _plot(); 899 | } 900 | 901 | // Row 9 902 | void 903 | DataAnalyzeController::setFieldList9(QString table) 904 | { 905 | tables[8] = table; 906 | 907 | QList itemList = MainWindow::getMainWindow()->ui().treeWidget->findItems(table, Qt::MatchCaseSensitive); 908 | for(int i=0; ichildCount(); j++){ 912 | _fieldList[8]<child(j)->text(0); 913 | } 914 | emit fieldList9Changed(); 915 | } 916 | _update_hide_tables(table); 917 | } 918 | 919 | void 920 | DataAnalyzeController::setField9(QString field){ 921 | fields[8] = field; 922 | if(field.compare("TimeUS") != 0) setVisible9(true); 923 | _plot(); 924 | } 925 | 926 | void 927 | DataAnalyzeController::setScale9(QString scale){ 928 | if(!_isNumber(scale)) return; 929 | 930 | _scale[8] = scale.left(scale.length()).toFloat(); 931 | _scale[8] = QString::number(_scale[8], 'f', 3).toFloat(); 932 | emit scale9Changed(); 933 | 934 | _plot(); 935 | } 936 | 937 | void 938 | DataAnalyzeController::setOffsetX9(QString offset){ 939 | if(!_isNumber(offset)) return; 940 | 941 | _offsetX[8] = (int)offset.left(offset.length()).toFloat(); 942 | emit offsetX9Changed(); 943 | 944 | _plot(); 945 | } 946 | 947 | void 948 | DataAnalyzeController::setOffsetY9(QString offset){ 949 | if(!_isNumber(offset)) return; 950 | 951 | _offsetY[8] = offset.left(offset.length()).toFloat(); 952 | _offsetY[8] = QString::number(_offsetY[8], 'f', 2).toFloat(); 953 | emit offsetY9Changed(); 954 | 955 | _plot(); 956 | } 957 | 958 | void 959 | DataAnalyzeController::setVisible9(bool visible){ 960 | _visible[8] = visible; 961 | emit visible9Changed(); 962 | 963 | _plot(); 964 | } 965 | 966 | void 967 | DataAnalyzeController::setLineStyle9(int style){ 968 | _style[8] = style; 969 | 970 | _plot(); 971 | } 972 | 973 | void 974 | DataAnalyzeController::setLineColor9(QString color){ 975 | _color[8] = _colorList.indexOf(color); 976 | 977 | _plot(); 978 | } 979 | 980 | // Row 10 981 | void 982 | DataAnalyzeController::setFieldList10(QString table) 983 | { 984 | tables[9] = table; 985 | 986 | QList itemList = MainWindow::getMainWindow()->ui().treeWidget->findItems(table, Qt::MatchCaseSensitive); 987 | for(int i=0; ichildCount(); j++){ 991 | _fieldList[9]<child(j)->text(0); 992 | } 993 | emit fieldList10Changed(); 994 | } 995 | _update_hide_tables(table); 996 | } 997 | 998 | void 999 | DataAnalyzeController::setField10(QString field){ 1000 | fields[9] = field; 1001 | if(field.compare("TimeUS") != 0) setVisible10(true); 1002 | _plot(); 1003 | } 1004 | 1005 | void 1006 | DataAnalyzeController::setScale10(QString scale){ 1007 | if(!_isNumber(scale)) return; 1008 | 1009 | _scale[9] = scale.left(scale.length()).toFloat(); 1010 | _scale[9] = QString::number(_scale[9], 'f', 3).toFloat(); 1011 | emit scale10Changed(); 1012 | 1013 | _plot(); 1014 | } 1015 | 1016 | void 1017 | DataAnalyzeController::setOffsetX10(QString offset){ 1018 | if(!_isNumber(offset)) return; 1019 | 1020 | _offsetX[9] = (int)offset.left(offset.length()).toFloat(); 1021 | emit offsetX10Changed(); 1022 | 1023 | _plot(); 1024 | } 1025 | 1026 | void 1027 | DataAnalyzeController::setOffsetY10(QString offset){ 1028 | if(!_isNumber(offset)) return; 1029 | 1030 | _offsetY[9] = offset.left(offset.length()).toFloat(); 1031 | _offsetY[9] = QString::number(_offsetY[9], 'f', 2).toFloat(); 1032 | emit offsetY10Changed(); 1033 | 1034 | _plot(); 1035 | } 1036 | 1037 | void 1038 | DataAnalyzeController::setVisible10(bool visible){ 1039 | _visible[9] = visible; 1040 | emit visible10Changed(); 1041 | 1042 | _plot(); 1043 | } 1044 | 1045 | void 1046 | DataAnalyzeController::setLineStyle10(int style){ 1047 | _style[9] = style; 1048 | 1049 | _plot(); 1050 | } 1051 | 1052 | void 1053 | DataAnalyzeController::setLineColor10(QString color){ 1054 | _color[9] = _colorList.indexOf(color); 1055 | 1056 | _plot(); 1057 | } 1058 | -------------------------------------------------------------------------------- /src/DataAnalyzeController.h: -------------------------------------------------------------------------------- 1 | #ifndef DATAANALYZECONTROLLER_H 2 | #define DATAANALYZECONTROLLER_H 3 | 4 | #include 5 | #include "APLLoggingCategory.h" 6 | #include "qcustomplot.h" 7 | 8 | Q_DECLARE_LOGGING_CATEGORY(DATA_ANALYZE_LOG) 9 | 10 | #define MAX_LINE_NUM 10 11 | 12 | class DataAnalyzeController : public QObject 13 | { 14 | Q_OBJECT 15 | public: 16 | DataAnalyzeController(); 17 | 18 | Q_PROPERTY(QStringList lineList READ lineList NOTIFY lineListChanged) 19 | Q_PROPERTY(QStringList colorList READ colorList NOTIFY colorListChanged) 20 | // Row 1 21 | Q_PROPERTY(QStringList tableList1 READ tableList1 NOTIFY tableList1Changed) 22 | Q_PROPERTY(bool visible1 READ visible1 NOTIFY visible1Changed) 23 | Q_PROPERTY(QStringList fieldList1 READ fieldList1 NOTIFY fieldList1Changed) 24 | Q_PROPERTY(QString scale1 READ scale1 NOTIFY scale1Changed) 25 | Q_PROPERTY(QString offsetX1 READ offsetX1 NOTIFY offsetX1Changed) 26 | Q_PROPERTY(QString offsetY1 READ offsetY1 NOTIFY offsetY1Changed) 27 | Q_PROPERTY(QStringList colorList1 READ colorList1 NOTIFY colorList1Changed) 28 | // Row 2 29 | Q_PROPERTY(QStringList tableList2 READ tableList2 NOTIFY tableList2Changed) 30 | Q_PROPERTY(bool visible2 READ visible2 NOTIFY visible2Changed) 31 | Q_PROPERTY(QStringList fieldList2 READ fieldList2 NOTIFY fieldList2Changed) 32 | Q_PROPERTY(QString scale2 READ scale2 NOTIFY scale2Changed) 33 | Q_PROPERTY(QString offsetX2 READ offsetX2 NOTIFY offsetX2Changed) 34 | Q_PROPERTY(QString offsetY2 READ offsetY2 NOTIFY offsetY2Changed) 35 | Q_PROPERTY(QStringList colorList2 READ colorList2 NOTIFY colorList2Changed) 36 | // Row 3 37 | Q_PROPERTY(QStringList tableList3 READ tableList3 NOTIFY tableList3Changed) 38 | Q_PROPERTY(bool visible3 READ visible3 NOTIFY visible3Changed) 39 | Q_PROPERTY(QStringList fieldList3 READ fieldList3 NOTIFY fieldList3Changed) 40 | Q_PROPERTY(QString scale3 READ scale3 NOTIFY scale3Changed) 41 | Q_PROPERTY(QString offsetX3 READ offsetX3 NOTIFY offsetX3Changed) 42 | Q_PROPERTY(QString offsetY3 READ offsetY3 NOTIFY offsetY3Changed) 43 | Q_PROPERTY(QStringList colorList3 READ colorList3 NOTIFY colorList3Changed) 44 | // Row 4 45 | Q_PROPERTY(QStringList tableList4 READ tableList4 NOTIFY tableList4Changed) 46 | Q_PROPERTY(bool visible4 READ visible4 NOTIFY visible4Changed) 47 | Q_PROPERTY(QStringList fieldList4 READ fieldList4 NOTIFY fieldList4Changed) 48 | Q_PROPERTY(QString scale4 READ scale4 NOTIFY scale4Changed) 49 | Q_PROPERTY(QString offsetX4 READ offsetX4 NOTIFY offsetX4Changed) 50 | Q_PROPERTY(QString offsetY4 READ offsetY4 NOTIFY offsetY4Changed) 51 | Q_PROPERTY(QStringList colorList4 READ colorList4 NOTIFY colorList4Changed) 52 | // Row 5 53 | Q_PROPERTY(QStringList tableList5 READ tableList5 NOTIFY tableList5Changed) 54 | Q_PROPERTY(bool visible5 READ visible5 NOTIFY visible5Changed) 55 | Q_PROPERTY(QStringList fieldList5 READ fieldList5 NOTIFY fieldList5Changed) 56 | Q_PROPERTY(QString scale5 READ scale5 NOTIFY scale5Changed) 57 | Q_PROPERTY(QString offsetX5 READ offsetX5 NOTIFY offsetX5Changed) 58 | Q_PROPERTY(QString offsetY5 READ offsetY5 NOTIFY offsetY5Changed) 59 | Q_PROPERTY(QStringList colorList5 READ colorList5 NOTIFY colorList5Changed) 60 | // Row 6 61 | Q_PROPERTY(QStringList tableList6 READ tableList6 NOTIFY tableList6Changed) 62 | Q_PROPERTY(bool visible6 READ visible6 NOTIFY visible6Changed) 63 | Q_PROPERTY(QStringList fieldList6 READ fieldList6 NOTIFY fieldList6Changed) 64 | Q_PROPERTY(QString scale6 READ scale6 NOTIFY scale6Changed) 65 | Q_PROPERTY(QString offsetX6 READ offsetX6 NOTIFY offsetX6Changed) 66 | Q_PROPERTY(QString offsetY6 READ offsetY6 NOTIFY offsetY6Changed) 67 | Q_PROPERTY(QStringList colorList6 READ colorList6 NOTIFY colorList6Changed) 68 | // Row 7 69 | Q_PROPERTY(QStringList tableList7 READ tableList7 NOTIFY tableList7Changed) 70 | Q_PROPERTY(bool visible7 READ visible7 NOTIFY visible7Changed) 71 | Q_PROPERTY(QStringList fieldList7 READ fieldList7 NOTIFY fieldList7Changed) 72 | Q_PROPERTY(QString scale7 READ scale7 NOTIFY scale7Changed) 73 | Q_PROPERTY(QString offsetX7 READ offsetX7 NOTIFY offsetX7Changed) 74 | Q_PROPERTY(QString offsetY7 READ offsetY7 NOTIFY offsetY7Changed) 75 | Q_PROPERTY(QStringList colorList7 READ colorList7 NOTIFY colorList7Changed) 76 | // Row 8 77 | Q_PROPERTY(QStringList tableList8 READ tableList8 NOTIFY tableList8Changed) 78 | Q_PROPERTY(bool visible8 READ visible8 NOTIFY visible8Changed) 79 | Q_PROPERTY(QStringList fieldList8 READ fieldList8 NOTIFY fieldList8Changed) 80 | Q_PROPERTY(QString scale8 READ scale8 NOTIFY scale8Changed) 81 | Q_PROPERTY(QString offsetX8 READ offsetX8 NOTIFY offsetX8Changed) 82 | Q_PROPERTY(QString offsetY8 READ offsetY8 NOTIFY offsetY8Changed) 83 | Q_PROPERTY(QStringList colorList8 READ colorList8 NOTIFY colorList8Changed) 84 | // Row 9 85 | Q_PROPERTY(QStringList tableList9 READ tableList9 NOTIFY tableList9Changed) 86 | Q_PROPERTY(bool visible9 READ visible9 NOTIFY visible9Changed) 87 | Q_PROPERTY(QStringList fieldList9 READ fieldList9 NOTIFY fieldList9Changed) 88 | Q_PROPERTY(QString scale9 READ scale9 NOTIFY scale9Changed) 89 | Q_PROPERTY(QString offsetX9 READ offsetX9 NOTIFY offsetX9Changed) 90 | Q_PROPERTY(QString offsetY9 READ offsetY9 NOTIFY offsetY9Changed) 91 | Q_PROPERTY(QStringList colorList9 READ colorList9 NOTIFY colorList9Changed) 92 | // Row 10 93 | Q_PROPERTY(QStringList tableList10 READ tableList10 NOTIFY tableList10Changed) 94 | Q_PROPERTY(bool visible10 READ visible10 NOTIFY visible10Changed) 95 | Q_PROPERTY(QStringList fieldList10 READ fieldList10 NOTIFY fieldList10Changed) 96 | Q_PROPERTY(QString scale10 READ scale10 NOTIFY scale10Changed) 97 | Q_PROPERTY(QString offsetX10 READ offsetX10 NOTIFY offsetX10Changed) 98 | Q_PROPERTY(QString offsetY10 READ offsetY10 NOTIFY offsetY10Changed) 99 | Q_PROPERTY(QStringList colorList10 READ colorList10 NOTIFY colorList10Changed) 100 | 101 | // Row 1 102 | Q_INVOKABLE void setFieldList1 (QString table); 103 | Q_INVOKABLE void setField1 (QString field); 104 | Q_INVOKABLE void setScale1 (QString scale); 105 | Q_INVOKABLE void setOffsetX1 (QString offset); 106 | Q_INVOKABLE void setOffsetY1 (QString offset); 107 | Q_INVOKABLE void setVisible1 (bool visible); 108 | Q_INVOKABLE void setLineStyle1 (int style); 109 | Q_INVOKABLE void setLineColor1 (QString color); 110 | // Row 2 111 | Q_INVOKABLE void setFieldList2 (QString table); 112 | Q_INVOKABLE void setField2 (QString field); 113 | Q_INVOKABLE void setScale2 (QString scale); 114 | Q_INVOKABLE void setOffsetX2 (QString offset); 115 | Q_INVOKABLE void setOffsetY2 (QString offset); 116 | Q_INVOKABLE void setVisible2 (bool visible); 117 | Q_INVOKABLE void setLineStyle2 (int style); 118 | Q_INVOKABLE void setLineColor2 (QString color); 119 | // Row 3 120 | Q_INVOKABLE void setFieldList3 (QString table); 121 | Q_INVOKABLE void setField3 (QString field); 122 | Q_INVOKABLE void setScale3 (QString scale); 123 | Q_INVOKABLE void setOffsetX3 (QString offset); 124 | Q_INVOKABLE void setOffsetY3 (QString offset); 125 | Q_INVOKABLE void setVisible3 (bool visible); 126 | Q_INVOKABLE void setLineStyle3 (int style); 127 | Q_INVOKABLE void setLineColor3 (QString color); 128 | // Row 4 129 | Q_INVOKABLE void setFieldList4 (QString table); 130 | Q_INVOKABLE void setField4 (QString field); 131 | Q_INVOKABLE void setScale4 (QString scale); 132 | Q_INVOKABLE void setOffsetX4 (QString offset); 133 | Q_INVOKABLE void setOffsetY4 (QString offset); 134 | Q_INVOKABLE void setVisible4 (bool visible); 135 | Q_INVOKABLE void setLineStyle4 (int style); 136 | Q_INVOKABLE void setLineColor4 (QString color); 137 | // Row 5 138 | Q_INVOKABLE void setFieldList5 (QString table); 139 | Q_INVOKABLE void setField5 (QString field); 140 | Q_INVOKABLE void setScale5 (QString scale); 141 | Q_INVOKABLE void setOffsetX5 (QString offset); 142 | Q_INVOKABLE void setOffsetY5 (QString offset); 143 | Q_INVOKABLE void setVisible5 (bool visible); 144 | Q_INVOKABLE void setLineStyle5 (int style); 145 | Q_INVOKABLE void setLineColor5 (QString color); 146 | // Row 6 147 | Q_INVOKABLE void setFieldList6 (QString table); 148 | Q_INVOKABLE void setField6 (QString field); 149 | Q_INVOKABLE void setScale6 (QString scale); 150 | Q_INVOKABLE void setOffsetX6 (QString offset); 151 | Q_INVOKABLE void setOffsetY6 (QString offset); 152 | Q_INVOKABLE void setVisible6 (bool visible); 153 | Q_INVOKABLE void setLineStyle6 (int style); 154 | Q_INVOKABLE void setLineColor6 (QString color); 155 | // Row 7 156 | Q_INVOKABLE void setFieldList7 (QString table); 157 | Q_INVOKABLE void setField7 (QString field); 158 | Q_INVOKABLE void setScale7 (QString scale); 159 | Q_INVOKABLE void setOffsetX7 (QString offset); 160 | Q_INVOKABLE void setOffsetY7 (QString offset); 161 | Q_INVOKABLE void setVisible7 (bool visible); 162 | Q_INVOKABLE void setLineStyle7 (int style); 163 | Q_INVOKABLE void setLineColor7 (QString color); 164 | // Row 8 165 | Q_INVOKABLE void setFieldList8 (QString table); 166 | Q_INVOKABLE void setField8 (QString field); 167 | Q_INVOKABLE void setScale8 (QString scale); 168 | Q_INVOKABLE void setOffsetX8 (QString offset); 169 | Q_INVOKABLE void setOffsetY8 (QString offset); 170 | Q_INVOKABLE void setVisible8 (bool visible); 171 | Q_INVOKABLE void setLineStyle8 (int style); 172 | Q_INVOKABLE void setLineColor8 (QString color); 173 | // Row 9 174 | Q_INVOKABLE void setFieldList9 (QString table); 175 | Q_INVOKABLE void setField9 (QString field); 176 | Q_INVOKABLE void setScale9 (QString scale); 177 | Q_INVOKABLE void setOffsetX9 (QString offset); 178 | Q_INVOKABLE void setOffsetY9 (QString offset); 179 | Q_INVOKABLE void setVisible9 (bool visible); 180 | Q_INVOKABLE void setLineStyle9 (int style); 181 | Q_INVOKABLE void setLineColor9 (QString color); 182 | // Row 10 183 | Q_INVOKABLE void setFieldList10 (QString table); 184 | Q_INVOKABLE void setField10 (QString field); 185 | Q_INVOKABLE void setScale10 (QString scale); 186 | Q_INVOKABLE void setOffsetX10 (QString offset); 187 | Q_INVOKABLE void setOffsetY10 (QString offset); 188 | Q_INVOKABLE void setVisible10 (bool visible); 189 | Q_INVOKABLE void setLineStyle10 (int style); 190 | Q_INVOKABLE void setLineColor10 (QString color); 191 | 192 | QStringList lineList () { return _lineList; } 193 | QStringList colorList () { return _colorList; } 194 | // Row 1 195 | QStringList tableList1 () { return _tableList1; } 196 | QStringList fieldList1 () { return _fieldList[0]; } 197 | QString scale1 () { return QString::number(_scale[0], 'f', 3); } 198 | QString offsetX1 () { return QString::number(_offsetX[0]); } 199 | QString offsetY1 () { return QString::number(_offsetY[0], 'f', 2); } 200 | bool visible1 () { return _visible[0]; } 201 | QStringList colorList1 () { return _available_colorList; } 202 | // Row 2 203 | QStringList tableList2 () { return _tableList2; } 204 | QStringList fieldList2 () { return _fieldList[1]; } 205 | QString scale2 () { return QString::number(_scale[1], 'f', 3); } 206 | QString offsetX2 () { return QString::number(_offsetX[1]); } 207 | QString offsetY2 () { return QString::number(_offsetY[1], 'f', 2); } 208 | bool visible2 () { return _visible[1]; } 209 | QStringList colorList2 () { return _available_colorList; } 210 | // Row 3 211 | QStringList tableList3 () { return _tableList3; } 212 | QStringList fieldList3 () { return _fieldList[2]; } 213 | QString scale3 () { return QString::number(_scale[2], 'f', 3); } 214 | QString offsetX3 () { return QString::number(_offsetX[2]); } 215 | QString offsetY3 () { return QString::number(_offsetY[2], 'f', 2); } 216 | bool visible3 () { return _visible[2]; } 217 | QStringList colorList3 () { return _available_colorList; } 218 | // Row 4 219 | QStringList tableList4 () { return _tableList4; } 220 | QStringList fieldList4 () { return _fieldList[3]; } 221 | QString scale4 () { return QString::number(_scale[3], 'f', 3); } 222 | QString offsetX4 () { return QString::number(_offsetX[3]); } 223 | QString offsetY4 () { return QString::number(_offsetY[3], 'f', 2); } 224 | bool visible4 () { return _visible[3]; } 225 | QStringList colorList4 () { return _available_colorList; } 226 | // Row 5 227 | QStringList tableList5 () { return _tableList5; } 228 | QStringList fieldList5 () { return _fieldList[4]; } 229 | QString scale5 () { return QString::number(_scale[4], 'f', 3); } 230 | QString offsetX5 () { return QString::number(_offsetX[4]); } 231 | QString offsetY5 () { return QString::number(_offsetY[4], 'f', 2); } 232 | bool visible5 () { return _visible[4]; } 233 | QStringList colorList5 () { return _available_colorList; } 234 | // Row 6 235 | QStringList tableList6 () { return _tableList6; } 236 | QStringList fieldList6 () { return _fieldList[5]; } 237 | QString scale6 () { return QString::number(_scale[5], 'f', 3); } 238 | QString offsetX6 () { return QString::number(_offsetX[5]); } 239 | QString offsetY6 () { return QString::number(_offsetY[5], 'f', 2); } 240 | bool visible6 () { return _visible[5]; } 241 | QStringList colorList6 () { return _available_colorList; } 242 | // Row 7 243 | QStringList tableList7 () { return _tableList7; } 244 | QStringList fieldList7 () { return _fieldList[6]; } 245 | QString scale7 () { return QString::number(_scale[6], 'f', 3); } 246 | QString offsetX7 () { return QString::number(_offsetX[6]); } 247 | QString offsetY7 () { return QString::number(_offsetY[6], 'f', 2); } 248 | bool visible7 () { return _visible[6]; } 249 | QStringList colorList7 () { return _available_colorList; } 250 | // Row 8 251 | QStringList tableList8 () { return _tableList8; } 252 | QStringList fieldList8 () { return _fieldList[7]; } 253 | QString scale8 () { return QString::number(_scale[7], 'f', 3); } 254 | QString offsetX8 () { return QString::number(_offsetX[7]); } 255 | QString offsetY8 () { return QString::number(_offsetY[7], 'f', 2); } 256 | bool visible8 () { return _visible[7]; } 257 | QStringList colorList8 () { return _available_colorList; } 258 | // Row 9 259 | QStringList tableList9 () { return _tableList9; } 260 | QStringList fieldList9 () { return _fieldList[8]; } 261 | QString scale9 () { return QString::number(_scale[8], 'f', 3); } 262 | QString offsetX9 () { return QString::number(_offsetX[8]); } 263 | QString offsetY9 () { return QString::number(_offsetY[8], 'f', 2); } 264 | bool visible9 () { return _visible[8]; } 265 | QStringList colorList9 () { return _available_colorList; } 266 | // Row 10 267 | QStringList tableList10 () { return _tableList10; } 268 | QStringList fieldList10 () { return _fieldList[9]; } 269 | QString scale10 () { return QString::number(_scale[9], 'f', 3); } 270 | QString offsetX10 () { return QString::number(_offsetX[9]); } 271 | QString offsetY10 () { return QString::number(_offsetY[9], 'f', 2); } 272 | bool visible10 () { return _visible[9]; } 273 | QStringList colorList10 () { return _available_colorList; } 274 | 275 | signals: 276 | void lineListChanged (); 277 | void colorListChanged (); 278 | // Row 1 279 | void tableList1Changed (); 280 | void fieldList1Changed (); 281 | void scale1Changed (); 282 | void offsetX1Changed (); 283 | void offsetY1Changed (); 284 | void visible1Changed (); 285 | void colorList1Changed (); 286 | // Row 2 287 | void tableList2Changed (); 288 | void fieldList2Changed (); 289 | void scale2Changed (); 290 | void offsetX2Changed (); 291 | void offsetY2Changed (); 292 | void visible2Changed (); 293 | void colorList2Changed (); 294 | // Row 3 295 | void tableList3Changed (); 296 | void fieldList3Changed (); 297 | void scale3Changed (); 298 | void offsetX3Changed (); 299 | void offsetY3Changed (); 300 | void visible3Changed (); 301 | void colorList3Changed (); 302 | // Row 4 303 | void tableList4Changed (); 304 | void fieldList4Changed (); 305 | void scale4Changed (); 306 | void offsetX4Changed (); 307 | void offsetY4Changed (); 308 | void visible4Changed (); 309 | void colorList4Changed (); 310 | // Row 5 311 | void tableList5Changed (); 312 | void fieldList5Changed (); 313 | void scale5Changed (); 314 | void offsetX5Changed (); 315 | void offsetY5Changed (); 316 | void visible5Changed (); 317 | void colorList5Changed (); 318 | // Row 6 319 | void tableList6Changed (); 320 | void fieldList6Changed (); 321 | void scale6Changed (); 322 | void offsetX6Changed (); 323 | void offsetY6Changed (); 324 | void visible6Changed (); 325 | void colorList6Changed (); 326 | // Row 7 327 | void tableList7Changed (); 328 | void fieldList7Changed (); 329 | void scale7Changed (); 330 | void offsetX7Changed (); 331 | void offsetY7Changed (); 332 | void visible7Changed (); 333 | void colorList7Changed (); 334 | // Row 8 335 | void tableList8Changed (); 336 | void fieldList8Changed (); 337 | void scale8Changed (); 338 | void offsetX8Changed (); 339 | void offsetY8Changed (); 340 | void visible8Changed (); 341 | void colorList8Changed (); 342 | // Row 9 343 | void tableList9Changed (); 344 | void fieldList9Changed (); 345 | void scale9Changed (); 346 | void offsetX9Changed (); 347 | void offsetY9Changed (); 348 | void visible9Changed (); 349 | void colorList9Changed (); 350 | // Row 10 351 | void tableList10Changed (); 352 | void fieldList10Changed (); 353 | void scale10Changed (); 354 | void offsetX10Changed (); 355 | void offsetY10Changed (); 356 | void visible10Changed (); 357 | void colorList10Changed (); 358 | 359 | void clear_alreadyPloted (); 360 | void plotGraph (QString tables, 361 | QString fields, 362 | int offsetX, 363 | float offsetY, 364 | float scale, 365 | int linestyle, 366 | int color, 367 | bool visible, 368 | bool from); // false:DataAnalyzeController,true:Other 369 | void clearGraph (); 370 | 371 | private slots: 372 | void _setTableList(QString table); 373 | 374 | private: 375 | bool _isNumber(QString n); 376 | void _plot(); 377 | void _lineStyle(int index, int i); 378 | void _update_colorList(); 379 | void _update_hide_tables(QString table); 380 | bool _visible[MAX_LINE_NUM]; 381 | QStringList _tableList; 382 | QStringList _tableList1; 383 | QStringList _tableList2; 384 | QStringList _tableList3; 385 | QStringList _tableList4; 386 | QStringList _tableList5; 387 | QStringList _tableList6; 388 | QStringList _tableList7; 389 | QStringList _tableList8; 390 | QStringList _tableList9; 391 | QStringList _tableList10; 392 | QStringList _lineList; 393 | QStringList _colorList; 394 | QStringList _available_colorList; 395 | QStringList _fieldList[MAX_LINE_NUM]; 396 | float _scale[MAX_LINE_NUM]; 397 | int _offsetX[MAX_LINE_NUM]; 398 | float _offsetY[MAX_LINE_NUM]; 399 | int _style[MAX_LINE_NUM]; 400 | int _color[MAX_LINE_NUM]; 401 | 402 | public: 403 | QString tables[MAX_LINE_NUM]; 404 | QString fields[MAX_LINE_NUM]; 405 | 406 | public slots: 407 | Q_INVOKABLE void init (); 408 | }; 409 | 410 | #endif // DATAANALYZECONTROLLER_H 411 | -------------------------------------------------------------------------------- /src/Dialog.cpp: -------------------------------------------------------------------------------- 1 | #include "Dialog.h" 2 | #include "APLRead.h" 3 | #include "APLDB.h" 4 | #include "mainwindow.h" 5 | #include 6 | 7 | APL_LOGGING_CATEGORY(DIALOG_LOG, "DialogLog") 8 | 9 | Dialog::Dialog(QWidget *parent) 10 | : QDialog(parent) 11 | , _aplRead(new APLRead) 12 | , _qfiledialog(new QFileDialog) 13 | { 14 | connect(_qfiledialog, &QFileDialog::fileSelected, _aplRead, &APLRead::getFileDir); 15 | } 16 | 17 | Dialog::~Dialog() 18 | { 19 | delete _aplRead; 20 | delete _qfiledialog; 21 | } 22 | 23 | void Dialog::showFile() 24 | { 25 | QString logdir = _qfiledialog->getOpenFileName(this 26 | ,"open ArduPilot binary log file" 27 | ,"/" 28 | ,"Binary files(*.bin *.BIN)"); 29 | emit _qfiledialog->fileSelected(logdir); 30 | 31 | qCDebug(DIALOG_LOG) << logdir; 32 | } 33 | 34 | void Dialog::saveFile() 35 | { 36 | QString dbdir = _qfiledialog->getSaveFileName(this 37 | ,"Save as DB file" 38 | ,_aplRead->getFileName().section('.',0,0)+".db" 39 | ,"DB files(*.db)"); 40 | 41 | if (!dbdir.isNull()) 42 | { 43 | QFile file_in, file_out; 44 | 45 | file_in.setFileName(QString(DB_FILE)); 46 | file_out.setFileName(dbdir); 47 | if(!file_in.open(QIODevice::ReadOnly)) 48 | { 49 | qCDebug(DIALOG_LOG)<< "can not open file: " << QString(DB_FILE); 50 | return; 51 | } else { 52 | if(file_out.open(QIODevice::ReadOnly)){ 53 | file_out.close(); 54 | QFile::remove(dbdir); 55 | qCDebug(DIALOG_LOG)<< "delete old file" << dbdir; 56 | } 57 | if(file_out.open(QIODevice::WriteOnly)){ 58 | QDataStream in(&file_in); 59 | QDataStream out(&file_out); 60 | while(!in.atEnd()) 61 | { 62 | quint8 currentByte; 63 | 64 | in >> currentByte; 65 | out << currentByte; 66 | } 67 | file_in.close(); 68 | file_out.close(); 69 | emit saveSuccess(); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Dialog.h: -------------------------------------------------------------------------------- 1 | #ifndef DIALOG_H 2 | #define DIALOG_H 3 | 4 | #include 5 | #include 6 | #include "APLLoggingCategory.h" 7 | 8 | Q_DECLARE_LOGGING_CATEGORY(DIALOG_LOG) 9 | 10 | class APLRead; 11 | class QFileDialog; 12 | 13 | class Dialog : public QDialog 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | Dialog(QWidget *parent = 0); 19 | ~Dialog(); 20 | 21 | APLRead* getAPLRead() const { return _aplRead; } 22 | 23 | public slots: 24 | void showFile(); 25 | void saveFile(); 26 | 27 | signals: 28 | void saveSuccess(); 29 | 30 | private: 31 | APLRead *_aplRead; 32 | QFileDialog *_qfiledialog; 33 | }; 34 | 35 | #endif // DIALOG_H 36 | -------------------------------------------------------------------------------- /src/DialogLoad.cpp: -------------------------------------------------------------------------------- 1 | #include "DialogLoad.h" 2 | #include "APLReadConf.h" 3 | #include "mainwindow.h" 4 | #include 5 | 6 | APL_LOGGING_CATEGORY(DialogLoad_LOG, "DialogLoadLog") 7 | 8 | DialogLoad::DialogLoad(QWidget *parent) 9 | : QDialog(parent) 10 | , _aplReadConf(new APLReadConf) 11 | , _qfileDialogLoad(new QFileDialog) 12 | { 13 | connect(_qfileDialogLoad, &QFileDialog::fileSelected, _aplReadConf, &APLReadConf::getFileDir); 14 | } 15 | 16 | DialogLoad::~DialogLoad() 17 | { 18 | delete _aplReadConf; 19 | delete _qfileDialogLoad; 20 | } 21 | 22 | void DialogLoad::showFile() 23 | { 24 | QString confdir = _qfileDialogLoad->getOpenFileName(this 25 | ,"open plot config" 26 | ,"/" 27 | ,"Config files(*.conf)"); 28 | emit _qfileDialogLoad->fileSelected(confdir); 29 | 30 | qCDebug(DialogLoad_LOG) << confdir; 31 | } 32 | 33 | void DialogLoad::saveFile() 34 | { 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/DialogLoad.h: -------------------------------------------------------------------------------- 1 | #ifndef DialogLoad_H 2 | #define DialogLoad_H 3 | 4 | #include 5 | #include 6 | #include "APLLoggingCategory.h" 7 | 8 | Q_DECLARE_LOGGING_CATEGORY(DialogLoad_LOG) 9 | 10 | class APLReadConf; 11 | class QFileDialog; 12 | 13 | class DialogLoad : public QDialog 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | DialogLoad(QWidget *parent = 0); 19 | ~DialogLoad(); 20 | 21 | APLReadConf* getAPLReadConf() const { return _aplReadConf; } 22 | 23 | public slots: 24 | void showFile(); 25 | void saveFile(); 26 | 27 | signals: 28 | void saveSuccess(); 29 | 30 | private: 31 | APLReadConf *_aplReadConf; 32 | QFileDialog *_qfileDialogLoad; 33 | }; 34 | 35 | #endif // DialogLoad_H 36 | -------------------------------------------------------------------------------- /src/LogStructure.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /* 6 | unfortunately these need to be macros because of a limitation of 7 | named member structure initialisation in g++ 8 | */ 9 | #define LOG_PACKET_HEADER uint8_t head1, head2, msgid 10 | #define LOG_PACKET_HEADER_INIT(id) head1 : HEAD_BYTE1, head2 : HEAD_BYTE2, msgid : id 11 | #define LOG_PACKET_HEADER_LEN 3 // bytes required for LOG_PACKET_HEADER 12 | 13 | // once the logging code is all converted we will remove these from 14 | // this header 15 | #define HEAD_BYTE1 0xA3 // Decimal 163 16 | #define HEAD_BYTE2 0x95 // Decimal 149 17 | 18 | // structure used to define logging format 19 | struct LogStructure { 20 | uint8_t msg_type; 21 | uint8_t msg_len; 22 | const char name[5]; 23 | const char format[16]; 24 | const char labels[64]; 25 | const char units[16]; 26 | const char multipliers[16]; 27 | }; 28 | 29 | /* 30 | log structures common to all vehicle types 31 | */ 32 | struct PACKED log_Format { 33 | LOG_PACKET_HEADER; 34 | uint8_t type; 35 | uint8_t length; 36 | char name[4]; 37 | char format[16]; 38 | char labels[64]; 39 | }; 40 | 41 | /* 42 | Format characters in the format string for binary log messages 43 | a : int16_t[32] 44 | b : int8_t 45 | B : uint8_t 46 | h : int16_t 47 | H : uint16_t 48 | i : int32_t 49 | I : uint32_t 50 | f : float 51 | d : double 52 | n : char[4] 53 | N : char[16] 54 | Z : char[64] 55 | c : int16_t * 100 56 | C : uint16_t * 100 57 | e : int32_t * 100 58 | E : uint32_t * 100 59 | L : int32_t latitude/longitude 60 | M : uint8_t flight mode 61 | q : int64_t 62 | Q : uint64_t 63 | */ 64 | 65 | 66 | // message types for common messages 67 | enum LogMessages { 68 | LOG_FORMAT_MSG = 128, 69 | }; 70 | --------------------------------------------------------------------------------