Commit c615f477 authored by Gus Grubba's avatar Gus Grubba

Finished. Needs testing and debugging.

parent 4d23912a
......@@ -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<MavlinkLogFiles*>(_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<MavlinkLogFiles*>(_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<MavlinkLogFiles*>(_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;
}
//-----------------------------------------------------------------------------
......
......@@ -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
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment