LP-106 Setup Wizard refresh : Add dual servo setup (dual aileron or
[librepilot.git] / ground / gcs / src / plugins / usagetracker / usagetrackerplugin.cpp
blobf8d4019048fb1e3c5c92a0b44d5f2abefad9d131
1 /**
2 ******************************************************************************
4 * @file usagetrackerplugin.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015.
6 * @addtogroup GCSPlugins GCS Plugins
7 * @{
8 * @addtogroup UsageTrackerPlugin Usage Tracker Plugin
9 * @{
10 * @brief A plugin tracking GCS usage
11 *****************************************************************************/
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "usagetrackerplugin.h"
28 #include <QtPlugin>
29 #include <QStringList>
30 #include <QtNetwork/QNetworkAccessManager>
31 #include <QtNetwork/QNetworkRequest>
32 #include <QtNetwork/QNetworkReply>
33 #include <extensionsystem/pluginmanager.h>
34 #include <QCheckBox>
35 #include <QDebug>
36 #include <QMessageBox>
37 #include <uavobjectutil/devicedescriptorstruct.h>
38 #include <uavobjectutil/uavobjectutilmanager.h>
39 #include "version_info/version_info.h"
40 #include "coreplugin/icore.h"
41 #include <uavtalk/telemetrymanager.h>
43 UsageTrackerPlugin::UsageTrackerPlugin() :
44 m_telemetryManager(NULL)
47 UsageTrackerPlugin::~UsageTrackerPlugin()
50 bool UsageTrackerPlugin::initialize(const QStringList & args, QString *errMsg)
52 Q_UNUSED(args);
53 Q_UNUSED(errMsg);
55 return true;
58 void UsageTrackerPlugin::extensionsInitialized()
60 ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
62 m_telemetryManager = pm->getObject<TelemetryManager>();
63 connect(m_telemetryManager, SIGNAL(connected()), this, SLOT(onAutopilotConnect()));
66 void UsageTrackerPlugin::shutdown()
68 if (m_telemetryManager != NULL) {
69 disconnect(m_telemetryManager, SIGNAL(connected()), this, SLOT(onAutopilotConnect()));
73 void UsageTrackerPlugin::onAutopilotConnect()
75 Core::Internal::GeneralSettings *settings = getGeneralSettings();
77 if (settings->collectUsageData()) {
78 if (settings->showUsageDataDisclaimer()) {
79 QMessageBox message;
80 message.setWindowTitle(tr("Usage feedback"));
81 message.setIcon(QMessageBox::Information);
82 message.addButton(tr("Yes, count me in"), QMessageBox::AcceptRole);
83 message.addButton(tr("No, I will not help"), QMessageBox::RejectRole);
84 message.setText(tr("%1 has a function to collect limited anonymous information about "
85 "the usage of the application itself and the hardware connected to it.<p>"
86 "The intention is to not include anything that can be considered sensitive "
87 "or a threat to the users integrity. The collected information will be sent "
88 "using a secure protocol to an %2 web service and stored in a database "
89 "for later analysis and statistical purposes.<br>"
90 "No information will be sold or given to any third party. The sole purpose is "
91 "to collect statistics about the usage of our software and hardware to enable us "
92 "to make things better for you.<p>"
93 "The following things are collected:<ul>"
94 "<li>Bootloader version</li>"
95 "<li>Firmware version, tag and git hash</li>"
96 "<li>Hardware type, revision and mcu serial number</li>"
97 "<li>Selected configuration parameters</li>"
98 "<li>GCS version</li>"
99 "<li>Operating system version and architecture</li>"
100 "<li>Current local time</li></ul>"
101 "The information is collected only at the time when a board is connecting to GCS.<p>"
102 "It is possible to enable or disable this functionality in the general "
103 "settings part of the options for the GCS application at any time.<p>"
104 "We need your help, with your feedback we know where to improve things and what "
105 "platforms are in use. This is a community project that depends on people being involved.<br>"
106 "Thank You for helping us making things better and for supporting %2!").arg(GCS_BIG_NAME).arg(ORG_BIG_NAME));
107 QCheckBox *disclaimerCb = new QCheckBox(tr("&Don't show this message again."));
108 disclaimerCb->setChecked(true);
109 message.setCheckBox(disclaimerCb);
110 if (message.exec() != QMessageBox::AcceptRole) {
111 settings->setCollectUsageData(false);
112 settings->setShowUsageDataDisclaimer(!message.checkBox()->isChecked());
113 return;
114 } else {
115 settings->setCollectUsageData(true);
116 settings->setShowUsageDataDisclaimer(!message.checkBox()->isChecked());
119 QTimer::singleShot(1000, this, SLOT(trackUsage()));
123 void UsageTrackerPlugin::trackUsage()
125 QMap<QString, QString> parameters;
126 collectUsageParameters(parameters);
128 QUrlQuery query;
129 QMapIterator<QString, QString> iter(parameters);
130 while (iter.hasNext()) {
131 iter.next();
132 query.addQueryItem(iter.key(), iter.value());
135 // Add checksum
136 QString hash = getQueryHash(query.toString());
138 if (shouldSend(hash)) {
139 query.addQueryItem("hash", hash);
141 QUrl url("https://www.librepilot.org/opver?" + query.toString(QUrl::FullyEncoded));
143 QNetworkAccessManager *networkAccessManager = new QNetworkAccessManager();
145 // This will delete the network access manager instance when we're done
146 connect(networkAccessManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinished(QNetworkReply *)));
147 connect(networkAccessManager, SIGNAL(finished(QNetworkReply *)), networkAccessManager, SLOT(deleteLater()));
149 qDebug() << "Sending usage tracking as:" << url.toEncoded(QUrl::FullyEncoded);
150 networkAccessManager->get(QNetworkRequest(QUrl(url.toEncoded(QUrl::FullyEncoded))));
154 void UsageTrackerPlugin::collectUsageParameters(QMap<QString, QString> &parameters)
156 ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
157 UAVObjectUtilManager *utilMngr = pm->getObject<UAVObjectUtilManager>();
159 QByteArray description = utilMngr->getBoardDescription();
160 deviceDescriptorStruct devDesc;
162 if (UAVObjectUtilManager::descriptionToStructure(description, devDesc)) {
163 int boardModel = utilMngr->getBoardModel();
164 parameters["board_type"] = "0x" + QString::number(boardModel, 16).toLower();
165 parameters["board_serial"] = utilMngr->getBoardCPUSerial().toHex();
166 parameters["bl_version"] = QString::number(utilMngr->getBootloaderRevision());
167 parameters["fw_tag"] = devDesc.gitTag;
168 parameters["fw_hash"] = devDesc.gitHash;
169 #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
170 parameters["os_version"] = QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture();
171 #else
172 parameters["os_version"] = "none";
173 #endif
174 parameters["os_threads"] = QString::number(QThread::idealThreadCount());
175 parameters["os_timezone"] = QTimeZone::systemTimeZoneId();
176 parameters["gcs_version"] = VersionInfo::revision();
178 // Configuration parameters
179 ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
180 UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
182 parameters["conf_receiver"] = getUAVFieldValue(objManager, "ManualControlSettings", "ChannelGroups", 0);
183 parameters["conf_vehicle"] = getUAVFieldValue(objManager, "SystemSettings", "AirframeType");
185 if ((boardModel & 0xff00) == 0x0400) {
186 // CopterControl family
187 parameters["conf_rport"] = getUAVFieldValue(objManager, "HwSettings", "CC_RcvrPort");
188 parameters["conf_mport"] = getUAVFieldValue(objManager, "HwSettings", "CC_MainPort");
189 parameters["conf_fport"] = getUAVFieldValue(objManager, "HwSettings", "CC_FlexiPort");
190 } else if ((boardModel & 0xff00) == 0x0900) {
191 // Revolution family
192 parameters["conf_rport"] = getUAVFieldValue(objManager, "HwSettings", "RM_RcvrPort");
193 parameters["conf_mport"] = getUAVFieldValue(objManager, "HwSettings", "RM_MainPort");
194 parameters["conf_fport"] = getUAVFieldValue(objManager, "HwSettings", "RM_FlexiPort");
195 parameters["conf_fusion"] = getUAVFieldValue(objManager, "RevoSettings", "FusionAlgorithm");
198 parameters["conf_uport"] = getUAVFieldValue(objManager, "HwSettings", "USB_HIDPort");
199 parameters["conf_vport"] = getUAVFieldValue(objManager, "HwSettings", "USB_VCPPort");
201 parameters["conf_rotation"] = QString("[%1:%2:%3]")
202 .arg(getUAVFieldValue(objManager, "AttitudeSettings", "BoardRotation", 0))
203 .arg(getUAVFieldValue(objManager, "AttitudeSettings", "BoardRotation", 1))
204 .arg(getUAVFieldValue(objManager, "AttitudeSettings", "BoardRotation", 2));
205 parameters["conf_pidr"] = QString("[%1:%2:%3:%4][%5:%6:%7:%8][%9:%10:%11:%12]")
206 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollRatePID", 0))
207 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollRatePID", 1))
208 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollRatePID", 2))
209 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollRatePID", 3))
210 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchRatePID", 0))
211 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchRatePID", 1))
212 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchRatePID", 2))
213 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchRatePID", 3))
214 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawRatePID", 0))
215 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawRatePID", 1))
216 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawRatePID", 2))
217 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawRatePID", 3));
218 parameters["conf_pia"] = QString("[%1:%2:%3][%4:%5:%6][%7:%8:%9]")
219 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollPI", 0))
220 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollPI", 1))
221 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "RollPI", 2))
222 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchPI", 0))
223 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchPI", 1))
224 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "PitchPI", 2))
225 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawPI", 0))
226 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawPI", 1))
227 .arg(getUAVFieldValue(objManager, "StabilizationSettingsBank1", "YawPI", 2));
229 parameters["conf_tps"] = getUAVFieldValue(objManager, "StabilizationSettingsBank1", "EnableThrustPIDScaling");
230 parameters["conf_piro"] = getUAVFieldValue(objManager, "StabilizationSettingsBank1", "EnablePiroComp");
232 parameters["conf_fmcount"] = getUAVFieldValue(objManager, "ManualControlSettings", "FlightModeNumber");
233 parameters["conf_fmodes"] = QString("[%1:%2:%3]").arg(getUAVFieldValue(objManager, "FlightModeSettings", "FlightModePosition", 0))
234 .arg(getUAVFieldValue(objManager, "FlightModeSettings", "FlightModePosition", 1))
235 .arg(getUAVFieldValue(objManager, "FlightModeSettings", "FlightModePosition", 2));
239 void UsageTrackerPlugin::onFinished(QNetworkReply *reply)
241 if (reply->error() == QNetworkReply::NoError) {
242 getGeneralSettings()->setLastUsageHash(m_lastHash);
243 qDebug() << "Updated last usage hash to:" << m_lastHash;
244 } else {
245 qDebug() << "Usage tracking failed with:" << reply->errorString();
249 QString UsageTrackerPlugin::getUAVFieldValue(UAVObjectManager *objManager, QString objectName, QString fieldName, int index) const
251 UAVObject *object = objManager->getObject(objectName);
253 if (object != NULL) {
254 UAVObjectField *field = object->getField(fieldName);
255 if (field != NULL) {
256 return field->getValue(index).toString();
259 return tr("Unknown");
262 QString UsageTrackerPlugin::getQueryHash(QString source) const
264 source += "OpenPilot Fuck Yeah!";
265 return QString(QCryptographicHash::hash(QByteArray(source.toStdString().c_str()), QCryptographicHash::Md5).toHex());
268 Core::Internal::GeneralSettings *UsageTrackerPlugin::getGeneralSettings() const
270 ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
271 Core::Internal::GeneralSettings *settings = pm->getObject<Core::Internal::GeneralSettings>();
273 return settings;
276 bool UsageTrackerPlugin::shouldSend(const QString &hash)
278 if (getGeneralSettings()->lastUsageHash() == hash) {
279 return false;
280 } else {
281 m_lastHash = hash;
282 return true;