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