Commit 4d23912a authored by Gus Grubba's avatar Gus Grubba

Receiving and writing logs.

Forcing QGC to use Mavlink V2 if vehicle supports it.
parent f91c5bef
......@@ -481,7 +481,7 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
_handleCommandAck(message);
break;
case MAVLINK_MSG_ID_AUTOPILOT_VERSION:
_handleAutopilotVersion(message);
_handleAutopilotVersion(link, message);
break;
case MAVLINK_MSG_ID_WIND_COV:
_handleWindCov(message);
......@@ -508,11 +508,17 @@ void Vehicle::_mavlinkMessageReceived(LinkInterface* link, mavlink_message_t mes
_uas->receiveMessage(message);
}
void Vehicle::_handleAutopilotVersion(mavlink_message_t& message)
void Vehicle::_handleAutopilotVersion(LinkInterface *link, mavlink_message_t& message)
{
mavlink_autopilot_version_t autopilotVersion;
mavlink_msg_autopilot_version_decode(&message, &autopilotVersion);
bool isMavlink2 = (autopilotVersion.capabilities & MAV_PROTOCOL_CAPABILITY_MAVLINK2) != 0;
if(isMavlink2) {
mavlink_status_t* mavlinkStatus = mavlink_get_channel_status(link->mavlinkChannel());
mavlinkStatus->flags &= ~MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
}
if (autopilotVersion.flight_sw_version != 0) {
int majorVersion, minorVersion, patchVersion;
FIRMWARE_VERSION_TYPE versionType;
......@@ -2002,7 +2008,6 @@ Vehicle::_ackMavlinkLogData(uint16_t sequence)
void
Vehicle::_handleMavlinkLoggingData(mavlink_message_t& message)
{
qDebug() << "MAVLINK_MSG_ID_LOGGING_DATA";
mavlink_logging_data_t log;
mavlink_msg_logging_data_decode(&message, &log);
emit mavlinkLogData(this, log.target_system, log.target_component, log.sequence, log.length, log.first_message_offset, log.data, false);
......@@ -2012,7 +2017,6 @@ Vehicle::_handleMavlinkLoggingData(mavlink_message_t& message)
void
Vehicle::_handleMavlinkLoggingDataAcked(mavlink_message_t& message)
{
qDebug() << "MAVLINK_MSG_ID_LOGGING_DATA_ACKED";
mavlink_logging_data_t log;
mavlink_msg_logging_data_decode(&message, &log);
_ackMavlinkLogData(log.sequence);
......
......@@ -692,7 +692,7 @@ private:
void _handleVibration(mavlink_message_t& message);
void _handleExtendedSysState(mavlink_message_t& message);
void _handleCommandAck(mavlink_message_t& message);
void _handleAutopilotVersion(mavlink_message_t& message);
void _handleAutopilotVersion(LinkInterface* link, mavlink_message_t& message);
void _handleHilActuatorControls(mavlink_message_t& message);
void _missionManagerError(int errorCode, const QString& errorMsg);
void _geoFenceManagerError(int errorCode, const QString& errorMsg);
......
......@@ -73,7 +73,7 @@ MAVLinkProtocol::MAVLinkProtocol(QGCApplication* app)
MAVLinkProtocol::~MAVLinkProtocol()
{
storeSettings();
#ifndef __mobile__
_closeLogFile();
#endif
......@@ -162,7 +162,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
if (!_linkMgr->links()->contains(link)) {
return;
}
// receiveMutex.lock();
mavlink_message_t message;
mavlink_status_t status;
......@@ -214,6 +214,8 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
{
decodedFirstPacket = true;
/*
* Handled in Vehicle.cc now.
mavlink_status_t* mavlinkStatus = mavlink_get_channel_status(mavlinkChannel);
if (!(mavlinkStatus->flags & MAVLINK_STATUS_FLAG_IN_MAVLINK1) && (mavlinkStatus->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1)) {
qDebug() << "switch to mavlink 2.0" << mavlinkStatus << mavlinkChannel << mavlinkStatus->flags;
......@@ -222,6 +224,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
qDebug() << "switch to mavlink 1.0" << mavlinkStatus << mavlinkChannel << mavlinkStatus->flags;
mavlinkStatus->flags |= MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
}
*/
if(message.msgid == MAVLINK_MSG_ID_RADIO_STATUS)
{
......@@ -255,7 +258,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
#ifndef __mobile__
// Log data
if (!_logSuspendError && !_logSuspendReplay && _tempLogFile.isOpen()) {
uint8_t buf[MAVLINK_MAX_PACKET_LEN+sizeof(quint64)];
......@@ -280,7 +283,7 @@ void MAVLinkProtocol::receiveBytes(LinkInterface* link, QByteArray b)
_stopLogging();
_logSuspendError = true;
}
// Check for the vehicle arming going by. This is used to trigger log save.
if (!_logPromptForSave && message.msgid == MAVLINK_MSG_ID_HEARTBEAT) {
mavlink_heartbeat_t state;
......@@ -412,7 +415,7 @@ bool MAVLinkProtocol::_closeLogFile(void)
return true;
}
}
return false;
}
......@@ -458,11 +461,11 @@ void MAVLinkProtocol::_stopLogging(void)
void MAVLinkProtocol::checkForLostLogFiles(void)
{
QDir tempDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
QString filter(QString("*.%1").arg(_logFileExtension));
QFileInfoList fileInfoList = tempDir.entryInfoList(QStringList(filter), QDir::Files);
qDebug() << "Orphaned log file count" << fileInfoList.count();
foreach(const QFileInfo fileInfo, fileInfoList) {
qDebug() << "Orphaned log file" << fileInfo.filePath();
if (fileInfo.size() == 0) {
......@@ -488,10 +491,10 @@ void MAVLinkProtocol::suspendLogForReplay(bool suspend)
void MAVLinkProtocol::deleteTempLogFiles(void)
{
QDir tempDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
QString filter(QString("*.%1").arg(_logFileExtension));
QFileInfoList fileInfoList = tempDir.entryInfoList(QStringList(filter), QDir::Files);
foreach(const QFileInfo fileInfo, fileInfoList) {
QFile::remove(fileInfo.filePath());
}
......
......@@ -30,7 +30,7 @@ static const char* kEnableAutoUploadKey = "EnableAutoUploadKey";
static const char* kEnableAutoStartKey = "EnableAutoStartKey";
//-----------------------------------------------------------------------------
MavlinkLogFiles::MavlinkLogFiles(MavlinkLogManager *manager, const QString& filePath)
MavlinkLogFiles::MavlinkLogFiles(MavlinkLogManager* manager, const QString& filePath)
: _manager(manager)
, _size(0)
, _selected(false)
......@@ -76,6 +76,9 @@ MavlinkLogManager::MavlinkLogManager(QGCApplication* app)
, _currentLogfile(NULL)
, _vehicle(NULL)
, _logRunning(false)
, _loggingDisabled(false)
, _currentSavingFileFd(NULL)
, _sequence(0)
{
//-- Get saved settings
QSettings settings;
......@@ -90,14 +93,17 @@ MavlinkLogManager::MavlinkLogManager(QGCApplication* app)
if(!QDir(_logPath).exists()) {
if(QDir().mkpath(_logPath)) {
qCCritical(MavlinkLogManagerLog) << "Could not create Mavlink log download path:" << _logPath;
_loggingDisabled = true;
}
}
//-- Load current list of logs
QDirIterator it(_logPath, QStringList() << "*.ulg", QDir::Files);
while(it.hasNext()) {
_logFiles.append(new MavlinkLogFiles(this, it.next()));
if(!_loggingDisabled) {
//-- Load current list of logs
QDirIterator it(_logPath, QStringList() << "*.ulg", QDir::Files);
while(it.hasNext()) {
_logFiles.append(new MavlinkLogFiles(this, it.next()));
}
qCDebug(MavlinkLogManagerLog) << "Mavlink logs directory:" << _logPath;
}
qCDebug(MavlinkLogManagerLog) << "Mavlink logs directory:" << _logPath;
}
//-----------------------------------------------------------------------------
......@@ -108,19 +114,19 @@ MavlinkLogManager::~MavlinkLogManager()
//-----------------------------------------------------------------------------
void
MavlinkLogManager::setToolbox(QGCToolbox *toolbox)
MavlinkLogManager::setToolbox(QGCToolbox* toolbox)
{
QGCTool::setToolbox(toolbox);
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
qmlRegisterUncreatableType<MavlinkLogManager>("QGroundControl.MavlinkLogManager", 1, 0, "MavlinkLogManager", "Reference only");
connect(toolbox->multiVehicleManager(), &MultiVehicleManager::activeVehicleChanged, this, &MavlinkLogManager::_activeVehicleChanged);
// _uploadURL = "http://192.168.1.21/px4";
// _uploadURL = "http://192.168.1.9:8080";
// _emailAddress = "gus.grubba.com";
// _description = "Test from QGroundControl - Discard";
// _sendLog("/Users/gus/github/work/logs/simulator.ulg");
QGCTool::setToolbox(toolbox);
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
qmlRegisterUncreatableType<MavlinkLogManager>("QGroundControl.MavlinkLogManager", 1, 0, "MavlinkLogManager", "Reference only");
if(!_loggingDisabled) {
connect(toolbox->multiVehicleManager(), &MultiVehicleManager::activeVehicleChanged, this, &MavlinkLogManager::_activeVehicleChanged);
}
// _uploadURL = "http://192.168.1.21/px4";
// _uploadURL = "http://192.168.1.9:8080";
// _emailAddress = "gus.grubba.com";
// _description = "Test from QGroundControl - Discard";
// _sendLog("/Users/gus/github/work/logs/simulator.ulg");
}
//-----------------------------------------------------------------------------
......@@ -190,7 +196,7 @@ MavlinkLogManager::uploadLog()
if(_currentLogfile) {
_currentLogfile->setUploading(false);
}
for(int i = 0; i < _logFiles.count(); i++ ) {
for(int i = 0; i < _logFiles.count(); i++) {
_currentLogfile = qobject_cast<MavlinkLogFiles*>(_logFiles.get(i));
Q_ASSERT(_currentLogfile);
if(_currentLogfile->selected()) {
......@@ -210,18 +216,49 @@ MavlinkLogManager::uploadLog()
emit busyChanged();
}
//-----------------------------------------------------------------------------
int
MavlinkLogManager::_getFirstSelected()
{
for(int i = 0; i < _logFiles.count(); i++) {
MavlinkLogFiles* f = qobject_cast<MavlinkLogFiles*>(_logFiles.get(i));
Q_ASSERT(f);
if(f->selected()) {
return i;
}
}
return -1;
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager::deleteLog()
{
//-- TODO
while (true) {
int idx = _getFirstSelected();
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();
}
}
//-----------------------------------------------------------------------------
void
MavlinkLogManager::cancelUpload()
{
for(int i = 0; i < _logFiles.count(); i++ ) {
for(int i = 0; i < _logFiles.count(); i++) {
MavlinkLogFiles* pLogFile = qobject_cast<MavlinkLogFiles*>(_logFiles.get(i));
Q_ASSERT(pLogFile);
if(pLogFile->selected() && pLogFile != _currentLogfile) {
......@@ -238,9 +275,11 @@ void
MavlinkLogManager::startLogging()
{
if(_vehicle) {
_vehicle->startMavlinkLog();
_logRunning = true;
emit logRunningChanged();
if(_createNewLog()) {
_vehicle->startMavlinkLog();
_logRunning = true;
emit logRunningChanged();
}
}
}
......@@ -252,6 +291,17 @@ MavlinkLogManager::stopLogging()
_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
}
}
}
}
......@@ -287,21 +337,23 @@ MavlinkLogManager::_sendLog(const QString& logFile)
qCCritical(MavlinkLogManagerLog) << "Log file missing:" << logFile;
return false;
}
QFile *file = new QFile(logFile);
QFile* file = new QFile(logFile);
if(!file || !file->open(QIODevice::ReadOnly)) {
if (file) delete file;
if(file) {
delete file;
}
qCCritical(MavlinkLogManagerLog) << "Could not open log file:" << logFile;
return false;
}
if(!_nam) {
_nam = new QNetworkAccessManager(this);
_nam = new QNetworkAccessManager(this);
}
QNetworkProxy savedProxy = _nam->proxy();
QNetworkProxy tempProxy;
tempProxy.setType(QNetworkProxy::DefaultProxy);
_nam->setProxy(tempProxy);
//-- Build POST request
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart emailPart = create_form_part("email", _emailAddress);
QHttpPart descriptionPart = create_form_part("description", _description);
QHttpPart sourcePart = create_form_part("source", "QGroundControl");
......@@ -319,7 +371,7 @@ MavlinkLogManager::_sendLog(const QString& logFile)
file->setParent(multiPart);
QNetworkRequest request(_uploadURL);
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
QNetworkReply *reply = _nam->post(request, multiPart);
QNetworkReply* reply = _nam->post(request, multiPart);
connect(reply, &QNetworkReply::finished, this, &MavlinkLogManager::_uploadFinished);
connect(this, &MavlinkLogManager::abortUpload, reply, &QNetworkReply::abort);
//connect(reply, &QNetworkReply::readyRead, this, &MavlinkLogManager::_dataAvailable);
......@@ -332,7 +384,7 @@ MavlinkLogManager::_sendLog(const QString& logFile)
//-----------------------------------------------------------------------------
bool
MavlinkLogManager::_processUploadResponse(int http_code, QByteArray &data)
MavlinkLogManager::_processUploadResponse(int http_code, QByteArray& data)
{
qCDebug(MavlinkLogManagerLog) << "Uploaded response:" << QString::fromUtf8(data);
emit readyRead(data);
......@@ -343,7 +395,7 @@ MavlinkLogManager::_processUploadResponse(int http_code, QByteArray &data)
void
MavlinkLogManager::_dataAvailable()
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if(!reply) {
return;
}
......@@ -355,7 +407,7 @@ MavlinkLogManager::_dataAvailable()
void
MavlinkLogManager::_uploadFinished()
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if(!reply) {
return;
}
......@@ -379,8 +431,9 @@ MavlinkLogManager::_uploadProgress(qint64 bytesSent, qint64 bytesTotal)
{
if(bytesTotal) {
qreal progress = (qreal)bytesSent / (qreal)bytesTotal;
if(_currentLogfile)
if(_currentLogfile) {
_currentLogfile->setProgress(progress);
}
}
qCDebug(MavlinkLogManagerLog) << bytesSent << "of" << bytesTotal;
}
......@@ -393,17 +446,15 @@ MavlinkLogManager::_activeVehicleChanged(Vehicle* vehicle)
// connects/disconnects. In reality, if QGC is connected to multiple vehicles,
// this is called each time the user switches from one vehicle to another. So
// far, I'm working on the assumption that multiple vehicles is a rare exception.
// Disconnect the previous one (if any)
if (_vehicle) {
if(_vehicle) {
disconnect(_vehicle, &Vehicle::armedChanged, this, &MavlinkLogManager::_armedChanged);
disconnect(_vehicle, &Vehicle::mavlinkLogData, this, &MavlinkLogManager::_mavlinkLogData);
_vehicle = NULL;
emit canStartLogChanged();
}
// Connect new system
if (vehicle)
{
if(vehicle) {
_vehicle = vehicle;
connect(_vehicle, &Vehicle::armedChanged, this, &MavlinkLogManager::_armedChanged);
connect(_vehicle, &Vehicle::mavlinkLogData, this, &MavlinkLogManager::_mavlinkLogData);
......@@ -413,10 +464,47 @@ 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*/)
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(sequence != _sequence) {
qCWarning(MavlinkLogManagerLog) << "Dropped Mavlink log data";
if(first_message < 255) {
data += first_message;
length -= first_message;
} else {
return;
}
}
if(fwrite(data, 1, length, _currentSavingFileFd) != (size_t)length) {
fclose(_currentSavingFileFd);
_currentSavingFileFd = NULL;
qCCritical(MavlinkLogManagerLog) << "Error writing Mavlink log file:" << _currentSavingFileStr;
_logRunning = false;
_vehicle->stopMavlinkLog();
emit logRunningChanged();
}
} else {
qCWarning(MavlinkLogManagerLog) << "Mavlink log data received when not expected.";
}
_sequence = sequence + 1;
}
//-----------------------------------------------------------------------------
bool
MavlinkLogManager::_createNewLog()
{
Q_UNUSED(data);
qDebug() << "Mavlink Log:" << sequence << length << first_message;
if(_currentSavingFileFd) {
fclose(_currentSavingFileFd);
}
_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();
}
_sequence = 0;
return _currentSavingFileFd != NULL;
}
//-----------------------------------------------------------------------------
......@@ -426,17 +514,11 @@ MavlinkLogManager::_armedChanged(bool armed)
if(_vehicle) {
if(armed) {
if(_enableAutoStart) {
_vehicle->startMavlinkLog();
_logRunning = true;
emit logRunningChanged();
startLogging();
}
} else {
if(_logRunning && _enableAutoStart) {
_vehicle->stopMavlinkLog();
emit logRunningChanged();
if(_enableAutoUpload) {
//-- TODO: Queue log for auto upload
}
stopLogging();
}
}
}
......
......@@ -131,6 +131,8 @@ private slots:
private:
bool _sendLog (const QString& logFile);
bool _processUploadResponse (int http_code, QByteArray &data);
bool _createNewLog ();
int _getFirstSelected ();
private:
QString _description;
......@@ -144,6 +146,10 @@ private:
MavlinkLogFiles* _currentLogfile;
Vehicle* _vehicle;
bool _logRunning;
bool _loggingDisabled;
FILE* _currentSavingFileFd;
QString _currentSavingFileStr;
uint16_t _sequence;
};
#endif
......@@ -37,12 +37,10 @@ Rectangle {
var selected = 0
for(var i = 0; i < QGroundControl.mavlinkLogManager.logFiles.count; i++) {
var logFile = QGroundControl.mavlinkLogManager.logFiles.get(i)
console.log(logFile.selected)
if(logFile.selected)
selected++
}
_selectedCount = selected
console.log(_selectedCount)
}
}
......@@ -296,26 +294,27 @@ Rectangle {
id: logFilesColumn
spacing: ScreenTools.defaultFontPixelWidth
anchors.centerIn: parent
width: ScreenTools.defaultFontPixelWidth * 68
Rectangle {
width: ScreenTools.defaultFontPixelWidth * 52
width: ScreenTools.defaultFontPixelWidth * 64
height: ScreenTools.defaultFontPixelHeight * 10
anchors.horizontalCenter: parent.horizontalCenter
color: qgcPal.windowShade
color: qgcPal.window
border.color: qgcPal.text
border.width: 0.5
ListView {
width: ScreenTools.defaultFontPixelWidth * 50
height: ScreenTools.defaultFontPixelHeight * 9
width: ScreenTools.defaultFontPixelWidth * 56
height: ScreenTools.defaultFontPixelHeight * 8.75
anchors.centerIn: parent
orientation: ListView.Vertical
model: QGroundControl.mavlinkLogManager.logFiles
clip: true
delegate: Rectangle {
width: ScreenTools.defaultFontPixelWidth * 48
width: ScreenTools.defaultFontPixelWidth * 52
height: ScreenTools.defaultFontPixelHeight * 1.25
color: index % 2 == 0 ? qgcPal.window : qgcPal.windowShade
anchors.horizontalCenter: parent.horizontalCenter;
color: qgcPal.window
Row {
width: ScreenTools.defaultFontPixelWidth * 46
width: ScreenTools.defaultFontPixelWidth * 50
anchors.centerIn: parent
spacing: ScreenTools.defaultFontPixelWidth
QGCCheckBox {
......@@ -327,10 +326,10 @@ Rectangle {
}
QGCLabel {
text: object.name
width: ScreenTools.defaultFontPixelWidth * 20
width: ScreenTools.defaultFontPixelWidth * 28
}
QGCLabel {
text: object.size
text: Number(object.size).toLocaleString(Qt.locale(), 'f', 0)
visible: !object.uploading
width: ScreenTools.defaultFontPixelWidth * 20;
horizontalAlignment: Text.AlignRight
......
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