diff --git a/src/uas/MavlinkLogManager.cc b/src/uas/MavlinkLogManager.cc index 17b1e8ecaf0858e9c421a27feb23e51398eae8de..655dd37ad95216b79c3f5cc096cc0a5022029a29 100644 --- a/src/uas/MavlinkLogManager.cc +++ b/src/uas/MavlinkLogManager.cc @@ -28,6 +28,7 @@ static const char* kPx4URLKey = "MavlinkLogURL"; static const char* kDefaultPx4URL = "http://logs.px4.io/upload"; static const char* kEnableAutoUploadKey = "EnableAutoUploadKey"; static const char* kEnableAutoStartKey = "EnableAutoStartKey"; +static const char* kEnableDeletetKey = "EnableDeleteKey"; //----------------------------------------------------------------------------- MavlinkLogFiles::MavlinkLogFiles(MavlinkLogManager* manager, const QString& filePath) @@ -42,6 +43,14 @@ MavlinkLogFiles::MavlinkLogFiles(MavlinkLogManager* manager, const QString& file _size = (quint32)fi.size(); } +//----------------------------------------------------------------------------- +void +MavlinkLogFiles::setSize(quint32 size) +{ + _size = size; + emit sizeChanged(); +} + //----------------------------------------------------------------------------- void MavlinkLogFiles::setSelected(bool selected) @@ -67,6 +76,14 @@ MavlinkLogFiles::setProgress(qreal progress) emit progressChanged(); } +//----------------------------------------------------------------------------- +void +MavlinkLogFiles::setWriting(bool writing) +{ + _writing = writing; + emit writingChanged(); +} + //----------------------------------------------------------------------------- MavlinkLogManager::MavlinkLogManager(QGCApplication* app) : QGCTool(app) @@ -77,8 +94,9 @@ MavlinkLogManager::MavlinkLogManager(QGCApplication* app) , _vehicle(NULL) , _logRunning(false) , _loggingDisabled(false) - , _currentSavingFileFd(NULL) + , _currentSavingFile(NULL) , _sequence(0) + , _deleteAfterUpload(false) { //-- Get saved settings QSettings settings; @@ -87,6 +105,7 @@ MavlinkLogManager::MavlinkLogManager(QGCApplication* app) setUploadURL(settings.value(kPx4URLKey, QString(kDefaultPx4URL)).toString()); setEnableAutoUpload(settings.value(kEnableAutoUploadKey, true).toBool()); setEnableAutoStart(settings.value(kEnableAutoStartKey, true).toBool()); + setDeleteAfterUpload(settings.value(kEnableDeletetKey, false).toBool()); //-- Logging location _logPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); _logPath += "/MavlinkLogs"; @@ -100,7 +119,7 @@ MavlinkLogManager::MavlinkLogManager(QGCApplication* app) //-- Load current list of logs QDirIterator it(_logPath, QStringList() << "*.ulg", QDir::Files); while(it.hasNext()) { - _logFiles.append(new MavlinkLogFiles(this, it.next())); + _insertNewLog(new MavlinkLogFiles(this, it.next())); } qCDebug(MavlinkLogManagerLog) << "Mavlink logs directory:" << _logPath; } @@ -182,9 +201,19 @@ MavlinkLogManager::setEnableAutoStart(bool enable) emit enableAutoStartChanged(); } +//----------------------------------------------------------------------------- +void +MavlinkLogManager::setDeleteAfterUpload(bool enable) +{ + _deleteAfterUpload = enable; + QSettings settings; + settings.setValue(kEnableDeletetKey, enable); + emit deleteAfterUploadChanged(); +} + //----------------------------------------------------------------------------- bool -MavlinkLogManager::busy() +MavlinkLogManager::uploading() { return _currentLogfile != NULL; } @@ -208,12 +237,32 @@ MavlinkLogManager::uploadLog() filePath += _currentLogfile->name(); filePath += ".ulg"; _sendLog(filePath); - emit busyChanged(); + emit uploadingChanged(); return; } } _currentLogfile = NULL; - emit busyChanged(); + emit uploadingChanged(); +} + +//----------------------------------------------------------------------------- +void +MavlinkLogManager::_insertNewLog(MavlinkLogFiles* newLog) +{ + //-- Simpler than trying to sort this thing + int count = _logFiles.count(); + if(!count) { + _logFiles.append(newLog); + } else { + for(int i = 0; i < count; i++) { + MavlinkLogFiles* f = qobject_cast(_logFiles.get(i)); + if(newLog->name() < f->name()) { + _logFiles.insert(i, newLog); + return; + } + } + _logFiles.append(newLog); + } } //----------------------------------------------------------------------------- @@ -239,21 +288,28 @@ MavlinkLogManager::deleteLog() if(idx < 0) { break; } - MavlinkLogFiles* f = qobject_cast(_logFiles.get(idx)); - QString filePath = _logPath; - filePath += "/"; - filePath += f->name(); - filePath += ".ulg"; - QFile gone(filePath); - if(!gone.remove()) { - qCWarning(MavlinkLogManagerLog) << "Could not delete Mavlink log file:" << _logPath; - } - _logFiles.removeAt(idx); - delete f; - emit logFilesChanged(); + MavlinkLogFiles* log = qobject_cast(_logFiles.get(idx)); + _deleteLog(log); } } +//----------------------------------------------------------------------------- +void +MavlinkLogManager::_deleteLog(MavlinkLogFiles* log) +{ + QString filePath = _logPath; + filePath += "/"; + filePath += log->name(); + filePath += ".ulg"; + QFile gone(filePath); + if(!gone.remove()) { + qCWarning(MavlinkLogManagerLog) << "Could not delete Mavlink log file:" << _logPath; + } + _logFiles.removeOne(log); + delete log; + emit logFilesChanged(); +} + //----------------------------------------------------------------------------- void MavlinkLogManager::cancelUpload() @@ -288,19 +344,24 @@ void MavlinkLogManager::stopLogging() { if(_vehicle) { + //-- Tell vehicle to stop sending logs _vehicle->stopMavlinkLog(); - _logRunning = false; - emit logRunningChanged(); - if(_currentSavingFileFd) { - fclose(_currentSavingFileFd); - _logFiles.append(new MavlinkLogFiles(this, _currentSavingFileStr)); - emit logFilesChanged(); - _currentSavingFileFd = NULL; - _currentSavingFileStr.clear(); - //-- TODO: If auto upload is set, schedule it - if(_enableAutoUpload) { - //-- Queue log for auto upload + if(_currentSavingFile) { + _currentSavingFile->close(); + if(_currentSavingFile->record) { + _currentSavingFile->record->setWriting(false); + if(_enableAutoUpload) { + //-- Queue log for auto upload (set selected flag) + _currentSavingFile->record->setSelected(true); + if(!uploading()) { + uploadLog(); + } + } } + delete _currentSavingFile; + _currentSavingFile = NULL; + _logRunning = false; + emit logRunningChanged(); } } } @@ -416,8 +477,14 @@ MavlinkLogManager::_uploadFinished() if(_processUploadResponse(http_code, data)) { qCDebug(MavlinkLogManagerLog) << "Log uploaded."; emit succeed(); + if(_deleteAfterUpload) { + if(_currentLogfile) { + _deleteLog(_currentLogfile); + _currentLogfile = NULL; + } + } } else { - qCDebug(MavlinkLogManagerLog) << QString("Log Upload Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); + qCWarning(MavlinkLogManagerLog) << QString("Log Upload Error: %1 status: %2").arg(reply->errorString(), reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()); emit failed(); } reply->deleteLater(); @@ -466,7 +533,7 @@ MavlinkLogManager::_activeVehicleChanged(Vehicle* vehicle) void MavlinkLogManager::_mavlinkLogData(Vehicle* /*vehicle*/, uint8_t /*target_system*/, uint8_t /*target_component*/, uint16_t sequence, uint8_t length, uint8_t first_message, const uint8_t* data, bool /*acked*/) { - if(_currentSavingFileFd) { + if(_currentSavingFile) { if(sequence != _sequence) { qCWarning(MavlinkLogManagerLog) << "Dropped Mavlink log data"; if(first_message < 255) { @@ -476,17 +543,26 @@ MavlinkLogManager::_mavlinkLogData(Vehicle* /*vehicle*/, uint8_t /*target_system return; } } - if(fwrite(data, 1, length, _currentSavingFileFd) != (size_t)length) { - fclose(_currentSavingFileFd); - _currentSavingFileFd = NULL; - qCCritical(MavlinkLogManagerLog) << "Error writing Mavlink log file:" << _currentSavingFileStr; + if(fwrite(data, 1, length, _currentSavingFile->fd) != (size_t)length) { + qCCritical(MavlinkLogManagerLog) << "Error writing Mavlink log file:" << _currentSavingFile->fileName; + delete _currentSavingFile; + _currentSavingFile = NULL; _logRunning = false; _vehicle->stopMavlinkLog(); emit logRunningChanged(); } } else { + length = 0; qCWarning(MavlinkLogManagerLog) << "Mavlink log data received when not expected."; } + //-- Update file size + if(_currentSavingFile) { + _currentSavingFile->close(); + if(_currentSavingFile->record) { + quint32 size = _currentSavingFile->record->size() + length; + _currentSavingFile->record->setSize(size); + } + } _sequence = sequence + 1; } @@ -494,17 +570,29 @@ MavlinkLogManager::_mavlinkLogData(Vehicle* /*vehicle*/, uint8_t /*target_system bool MavlinkLogManager::_createNewLog() { - if(_currentSavingFileFd) { - fclose(_currentSavingFileFd); + if(_currentSavingFile) { + delete _currentSavingFile; + _currentSavingFile = NULL; } - _currentSavingFileStr.sprintf("%s/%03d-%s.ulg", _logPath.toLatin1().data(), _vehicle->id(), QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz").toLatin1().data()); - _currentSavingFileFd = fopen(_currentSavingFileStr.toLatin1().data(), "wb"); - if(!_currentSavingFileFd) { - qCCritical(MavlinkLogManagerLog) << "Could not create Mavlink log file:" << _currentSavingFileStr; - _currentSavingFileStr.clear(); + _currentSavingFile = new CurrentRunningLog; + _currentSavingFile->fileName.sprintf("%s/%03d-%s.ulg", + _logPath.toLatin1().data(), + _vehicle->id(), + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz").toLatin1().data()); + _currentSavingFile->fd = fopen(_currentSavingFile->fileName.toLatin1().data(), "wb"); + if(_currentSavingFile->fd) { + MavlinkLogFiles* newLog = new MavlinkLogFiles(this, _currentSavingFile->fileName); + newLog->setWriting(true); + _insertNewLog(newLog); + _currentSavingFile->record = newLog; + emit logFilesChanged(); + } else { + qCCritical(MavlinkLogManagerLog) << "Could not create Mavlink log file:" << _currentSavingFile->fileName; + delete _currentSavingFile; + _currentSavingFile = NULL; } _sequence = 0; - return _currentSavingFileFd != NULL; + return _currentSavingFile != NULL; } //----------------------------------------------------------------------------- diff --git a/src/uas/MavlinkLogManager.h b/src/uas/MavlinkLogManager.h index 7f5cf859448bbb46b262f4270a53ce9c0608c72e..aabe10413ba49ac3784693f782c3cf85aa587036 100644 --- a/src/uas/MavlinkLogManager.h +++ b/src/uas/MavlinkLogManager.h @@ -31,25 +31,31 @@ public: MavlinkLogFiles (MavlinkLogManager* manager, const QString& filePath); Q_PROPERTY(QString name READ name CONSTANT) - Q_PROPERTY(quint32 size READ size CONSTANT) + Q_PROPERTY(quint32 size READ size NOTIFY sizeChanged) Q_PROPERTY(bool selected READ selected WRITE setSelected NOTIFY selectedChanged) Q_PROPERTY(bool uploading READ uploading NOTIFY uploadingChanged) Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) + Q_PROPERTY(bool writing READ writing NOTIFY writingChanged) QString name () { return _name; } quint32 size () { return _size; } bool selected () { return _selected; } bool uploading () { return _uploading; } qreal progress () { return _progress; } + bool writing () { return _writing; } void setSelected (bool selected); void setUploading (bool uploading); void setProgress (qreal progress); + void setWriting (bool writing); + void setSize (quint32 size); signals: + void sizeChanged (); void selectedChanged (); void uploadingChanged (); void progressChanged (); + void writingChanged (); private: MavlinkLogManager* _manager; @@ -58,8 +64,37 @@ private: bool _selected; bool _uploading; qreal _progress; + bool _writing; }; +//----------------------------------------------------------------------------- +class CurrentRunningLog +{ +public: + CurrentRunningLog() + : fd(NULL) + , record(NULL) + , written(0) + { + } + ~CurrentRunningLog() + { + close(); + } + void close() + { + if(fd) { + fclose(fd); + fd = NULL; + } + } + FILE* fd; + QString fileName; + MavlinkLogFiles* record; + quint32 written; +}; + +//----------------------------------------------------------------------------- class MavlinkLogManager : public QGCTool { Q_OBJECT @@ -73,7 +108,8 @@ public: Q_PROPERTY(QString uploadURL READ uploadURL WRITE setUploadURL NOTIFY uploadURLChanged) Q_PROPERTY(bool enableAutoUpload READ enableAutoUpload WRITE setEnableAutoUpload NOTIFY enableAutoUploadChanged) Q_PROPERTY(bool enableAutoStart READ enableAutoStart WRITE setEnableAutoStart NOTIFY enableAutoStartChanged) - Q_PROPERTY(bool busy READ busy NOTIFY busyChanged) + Q_PROPERTY(bool deleteAfterUpload READ deleteAfterUpload WRITE setDeleteAfterUpload NOTIFY deleteAfterUploadChanged) + Q_PROPERTY(bool uploading READ uploading NOTIFY uploadingChanged) Q_PROPERTY(bool logRunning READ logRunning NOTIFY logRunningChanged) Q_PROPERTY(bool canStartLog READ canStartLog NOTIFY canStartLogChanged) Q_PROPERTY(QmlObjectListModel* logFiles READ logFiles NOTIFY logFilesChanged) @@ -89,9 +125,10 @@ public: QString uploadURL () { return _uploadURL; } bool enableAutoUpload () { return _enableAutoUpload; } bool enableAutoStart () { return _enableAutoStart; } - bool busy (); + bool uploading (); bool logRunning () { return _logRunning; } bool canStartLog () { return _vehicle != NULL; } + bool deleteAfterUpload () { return _deleteAfterUpload; } QmlObjectListModel* logFiles () { return &_logFiles; } @@ -100,6 +137,7 @@ public: void setUploadURL (QString url); void setEnableAutoUpload (bool enable); void setEnableAutoStart (bool enable); + void setDeleteAfterUpload(bool enable); // Override from QGCTool void setToolbox (QGCToolbox *toolbox); @@ -112,13 +150,14 @@ signals: void enableAutoStartChanged (); void logFilesChanged (); void selectedCountChanged (); - void busyChanged (); + void uploadingChanged (); void readyRead (QByteArray data); void failed (); void succeed (); void abortUpload (); void logRunningChanged (); void canStartLogChanged (); + void deleteAfterUploadChanged (); private slots: void _uploadFinished (); @@ -133,6 +172,8 @@ private: bool _processUploadResponse (int http_code, QByteArray &data); bool _createNewLog (); int _getFirstSelected (); + void _insertNewLog (MavlinkLogFiles* newLog); + void _deleteLog (MavlinkLogFiles* log); private: QString _description; @@ -147,9 +188,9 @@ private: Vehicle* _vehicle; bool _logRunning; bool _loggingDisabled; - FILE* _currentSavingFileFd; - QString _currentSavingFileStr; + CurrentRunningLog* _currentSavingFile; uint16_t _sequence; + bool _deleteAfterUpload; }; #endif diff --git a/src/ui/preferences/MavlinkSettings.qml b/src/ui/preferences/MavlinkSettings.qml index c5b34c9762a884129adf844c0855e58e1e930bba..f7ea0101aa74be5947706b99c7a737ddbd8ce5d6 100644 --- a/src/ui/preferences/MavlinkSettings.qml +++ b/src/ui/preferences/MavlinkSettings.qml @@ -262,6 +262,7 @@ Rectangle { //----------------------------------------------------------------- //-- Automatic Upload QGCCheckBox { + id: autoUploadCheck text: qsTr("Enable automatic log uploads") checked: QGroundControl.mavlinkLogManager.enableAutoUpload enabled: emailField.text !== "" && urlField !== "" @@ -269,6 +270,16 @@ Rectangle { QGroundControl.mavlinkLogManager.enableAutoUpload = checked } } + //----------------------------------------------------------------- + //-- Delete log after upload + QGCCheckBox { + text: qsTr("Delete log file after uploading") + checked: QGroundControl.mavlinkLogManager.deleteAfterUpload + enabled: emailField.text !== "" && urlField !== "" && autoUploadCheck.checked + onClicked: { + QGroundControl.mavlinkLogManager.deleteAfterUpload = checked + } + } } } //----------------------------------------------------------------- @@ -327,11 +338,13 @@ Rectangle { QGCLabel { text: object.name width: ScreenTools.defaultFontPixelWidth * 28 + color: object.writing ? qgcPal.warningText : qgcPal.text } QGCLabel { text: Number(object.size).toLocaleString(Qt.locale(), 'f', 0) visible: !object.uploading width: ScreenTools.defaultFontPixelWidth * 20; + color: object.writing ? qgcPal.warningText : qgcPal.text horizontalAlignment: Text.AlignRight } ProgressBar { @@ -352,7 +365,7 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter QGCButton { text: "Check All" - enabled: !QGroundControl.mavlinkLogManager.busy + enabled: !QGroundControl.mavlinkLogManager.uploading && !QGroundControl.mavlinkLogManager.logRunning onClicked: { for(var i = 0; i < QGroundControl.mavlinkLogManager.logFiles.count; i++) { var logFile = QGroundControl.mavlinkLogManager.logFiles.get(i) @@ -362,7 +375,7 @@ Rectangle { } QGCButton { text: "Check None" - enabled: !QGroundControl.mavlinkLogManager.busy + enabled: !QGroundControl.mavlinkLogManager.uploading && !QGroundControl.mavlinkLogManager.logRunning onClicked: { for(var i = 0; i < QGroundControl.mavlinkLogManager.logFiles.count; i++) { var logFile = QGroundControl.mavlinkLogManager.logFiles.get(i) @@ -372,7 +385,7 @@ Rectangle { } QGCButton { text: "Delete Selected" - enabled: _selectedCount > 0 && !QGroundControl.mavlinkLogManager.busy + enabled: _selectedCount > 0 && !QGroundControl.mavlinkLogManager.uploading && !QGroundControl.mavlinkLogManager.logRunning onClicked: deleteDialog.open() MessageDialog { id: deleteDialog @@ -388,8 +401,8 @@ Rectangle { } QGCButton { text: "Upload Selected" - enabled: _selectedCount > 0 && !QGroundControl.mavlinkLogManager.busy - visible: !QGroundControl.mavlinkLogManager.busy + enabled: _selectedCount > 0 && !QGroundControl.mavlinkLogManager.uploading && !QGroundControl.mavlinkLogManager.logRunning + visible: !QGroundControl.mavlinkLogManager.uploading onClicked: { QGroundControl.mavlinkLogManager.emailAddress = emailField.text if(QGroundControl.mavlinkLogManager.emailAddress === "") @@ -411,8 +424,8 @@ Rectangle { } QGCButton { text: "Cancel" - enabled: QGroundControl.mavlinkLogManager.busy - visible: QGroundControl.mavlinkLogManager.busy + enabled: QGroundControl.mavlinkLogManager.uploading && !QGroundControl.mavlinkLogManager.logRunning + visible: QGroundControl.mavlinkLogManager.uploading onClicked: cancelDialog.open() MessageDialog { id: cancelDialog