Browse Source

Merge pull request #2741 from NaterGator/logdl-fixes

Improvements to Log Downloading
QGC4.4
Lorenz Meier 9 years ago
parent
commit
4f0562b9e7
  1. 162
      src/ViewWidgets/LogDownloadController.cc
  2. 19
      src/ViewWidgets/LogDownloadController.h
  3. 1
      src/ui/MAVLinkDecoder.cc

162
src/ViewWidgets/LogDownloadController.cc

@ -36,10 +36,51 @@
#include <QUrl> #include <QUrl>
#define kTimeOutMilliseconds 500 #define kTimeOutMilliseconds 500
#define kGUIRateMilliseconds 17
#define kTableBins 128
#define kChunkSize (kTableBins * MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN)
QGC_LOGGING_CATEGORY(LogDownloadLog, "LogDownloadLog") QGC_LOGGING_CATEGORY(LogDownloadLog, "LogDownloadLog")
static QLocale kLocale; static QLocale kLocale;
//-----------------------------------------------------------------------------
struct LogDownloadData {
LogDownloadData(QGCLogEntry* entry);
QBitArray chunk_table;
uint32_t current_chunk;
QFile file;
QString filename;
uint ID;
QGCLogEntry* entry;
uint written;
QElapsedTimer elapsed;
void advanceChunk()
{
current_chunk++;
chunk_table = QBitArray(chunkBins(), false);
}
// The number of MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN bins in the current chunk
uint32_t chunkBins() const
{
return qMin(qCeil((entry->size() - current_chunk*kChunkSize)/static_cast<qreal>(MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN)),
kTableBins);
}
// The number of kChunkSize chunks in the file
uint32_t numChunks() const
{
return qCeil(entry->size() / static_cast<qreal>(kChunkSize));
}
// True if all bins in the chunk have been set to val
bool chunkEquals(const bool val) const
{
return chunk_table == QBitArray(chunk_table.size(), val);
}
};
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
LogDownloadData::LogDownloadData(QGCLogEntry* entry_) LogDownloadData::LogDownloadData(QGCLogEntry* entry_)
@ -274,36 +315,62 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui
qWarning() << "Received log data for wrong log"; qWarning() << "Received log data for wrong log";
return; return;
} }
if ((ofs % MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN) != 0) {
qWarning() << "Ignored misaligned incoming packet @" << ofs;
return;
}
bool result = false; bool result = false;
//-- Find offset table entry uint32_t timeout_time = kTimeOutMilliseconds;
uint o_index = ofs / MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN; if(ofs <= _downloadData->entry->size()) {
if(o_index <= (uint)_downloadData->offsets.count()) { const uint32_t chunk = ofs / kChunkSize;
_downloadData->offsets[o_index] = count; if (chunk != _downloadData->current_chunk) {
qWarning() << "Ignored packet for out of order chunk" << chunk;
return;
}
const uint16_t bin = (ofs - chunk*kChunkSize) / MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN;
if (bin >= _downloadData->chunk_table.size()) {
qWarning() << "Out of range bin received";
} else
_downloadData->chunk_table.setBit(bin);
if (_downloadData->file.pos() != ofs) {
// Seek to correct position
if (!_downloadData->file.seek(ofs)) {
qWarning() << "Error while seeking log file offset";
return;
}
}
//-- Write chunk to file //-- Write chunk to file
if(_downloadData->file.seek(ofs)) {
if(_downloadData->file.write((const char*)data, count)) { if(_downloadData->file.write((const char*)data, count)) {
_downloadData->written += count; _downloadData->written += count;
if (_downloadData->elapsed.elapsed() >= kGUIRateMilliseconds) {
//-- Update status //-- Update status
QString comma_value = kLocale.toString(_downloadData->written); QString comma_value = kLocale.toString(_downloadData->written);
_downloadData->entry->setStatus(comma_value); _downloadData->entry->setStatus(comma_value);
_downloadData->elapsed.start();
}
result = true; result = true;
//-- reset retries //-- reset retries
_retries = 0; _retries = 0;
//-- Reset timer //-- Reset timer
_timer.start(kTimeOutMilliseconds); _timer.start(timeout_time);
//-- Do we have it all? //-- Do we have it all?
if(_logComplete()) { if(_logComplete()) {
_downloadData->entry->setStatus(QString("Downloaded")); _downloadData->entry->setStatus(QString("Downloaded"));
//-- Check for more //-- Check for more
_receivedAllData(); _receivedAllData();
} else if (_chunkComplete()) {
_downloadData->advanceChunk();
_requestLogData(_downloadData->ID,
_downloadData->current_chunk*kChunkSize,
_downloadData->chunk_table.size()*MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN);
} }
} else { } else {
qWarning() << "Error while writing log file chunk"; qWarning() << "Error while writing log file chunk";
} }
} else { } else {
qWarning() << "Error while seeking log file offset";
}
} else {
qWarning() << "Received log offset greater than expected"; qWarning() << "Received log offset greater than expected";
} }
if(!result) { if(!result) {
@ -311,18 +378,19 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui
} }
} }
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
bool bool
LogDownloadController::_logComplete() LogDownloadController::_chunkComplete() const
{ {
//-- Iterate entries and look for a gap return _downloadData->chunkEquals(true);
int num_ofs = _downloadData->offsets.count();
for(int i = 0; i < num_ofs; i++) {
if(_downloadData->offsets[i] == 0) {
return false;
}
} }
return true;
//----------------------------------------------------------------------------------------
bool
LogDownloadController::_logComplete() const
{
return _chunkComplete() && (_downloadData->current_chunk+1) == _downloadData->numChunks();
} }
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
@ -333,7 +401,7 @@ LogDownloadController::_receivedAllData()
//-- Anything queued up for download? //-- Anything queued up for download?
if(_prepareLogDownload()) { if(_prepareLogDownload()) {
//-- Request Log //-- Request Log
_requestLogData(_downloadData->ID, 0, _downloadData->entry->size()); _requestLogData(_downloadData->ID, 0, _downloadData->chunk_table.size()*MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN);
} else { } else {
_resetSelection(); _resetSelection();
_setDownloading(false); _setDownloading(false);
@ -344,25 +412,13 @@ LogDownloadController::_receivedAllData()
void void
LogDownloadController::_findMissingData() LogDownloadController::_findMissingData()
{ {
int start = -1; if (_logComplete()) {
int end = -1; _receivedAllData();
int num_ofs = _downloadData->offsets.count(); return;
//-- Iterate offsets and look for a gap } else if (_chunkComplete()) {
for(int i = 0; i < num_ofs; i++) { _downloadData->advanceChunk();
if(_downloadData->offsets[i] == 0) {
if(start < 0)
start = i;
else
end = i;
} else {
if(start >= 0) {
break;
}
}
} }
//-- Is there something missing?
if(start >= 0) {
//-- Have we tried too many times?
if(_retries++ > 2) { if(_retries++ > 2) {
_downloadData->entry->setStatus(QString("Timed Out")); _downloadData->entry->setStatus(QString("Timed Out"));
//-- Give up //-- Give up
@ -370,18 +426,24 @@ LogDownloadController::_findMissingData()
_receivedAllData(); _receivedAllData();
return; return;
} }
//-- Is it a sequence or just one entry?
if(end < 0) { uint16_t start = 0, end = 0;
end = start; const int size = _downloadData->chunk_table.size();
for (; start < size; start++) {
if (!_downloadData->chunk_table.testBit(start)) {
break;
}
}
for (end = start; end < size; end++) {
if (_downloadData->chunk_table.testBit(end)) {
break;
} }
//-- Request these log chunks again
_requestLogData(
_downloadData->ID,
(uint32_t)(start * MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN),
(uint32_t)((end - start + 1) * MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN));
} else {
_receivedAllData();
} }
const uint32_t pos = _downloadData->current_chunk*kChunkSize + start*MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN,
len = (end - start)*MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN;
_requestLogData(_downloadData->ID, pos, len);
} }
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
@ -534,11 +596,9 @@ LogDownloadController::_prepareLogDownload()
if(!_downloadData->file.resize(entry->size())) { if(!_downloadData->file.resize(entry->size())) {
qWarning() << "Failed to allocate space for log file:" << _downloadData->filename; qWarning() << "Failed to allocate space for log file:" << _downloadData->filename;
} else { } else {
//-- Prepare Offset Table _downloadData->current_chunk = 0;
uint o_count = (uint)ceil(entry->size() / (double)MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN); _downloadData->chunk_table = QBitArray(_downloadData->chunkBins(), false);
for(uint i = 0; i < o_count; i++) { _downloadData->elapsed.start();
_downloadData->offsets.append(0);
}
result = true; result = true;
} }
} }

19
src/ViewWidgets/LogDownloadController.h

@ -28,6 +28,7 @@
#include <QTimer> #include <QTimer>
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QLocale> #include <QLocale>
#include <QElapsedTimer>
#include <memory> #include <memory>
@ -39,7 +40,7 @@ class MultiVehicleManager;
class UASInterface; class UASInterface;
class Vehicle; class Vehicle;
class QGCLogEntry; class QGCLogEntry;
class LogDownloadData; struct LogDownloadData;
Q_DECLARE_LOGGING_CATEGORY(LogDownloadLog) Q_DECLARE_LOGGING_CATEGORY(LogDownloadLog)
@ -122,19 +123,6 @@ private:
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class LogDownloadData {
public:
LogDownloadData(QGCLogEntry* entry);
QList<uint> offsets;
QFile file;
QString filename;
uint ID;
QTimer processDataTimer;
QGCLogEntry* entry;
uint written;
};
//-----------------------------------------------------------------------------
class LogDownloadController : public FactPanelController class LogDownloadController : public FactPanelController
{ {
Q_OBJECT Q_OBJECT
@ -170,7 +158,8 @@ private slots:
private: private:
bool _entriesComplete (); bool _entriesComplete ();
bool _logComplete (); bool _chunkComplete () const;
bool _logComplete () const;
void _findMissingEntries(); void _findMissingEntries();
void _receivedAllEntries(); void _receivedAllEntries();
void _receivedAllData (); void _receivedAllData ();

1
src/ui/MAVLinkDecoder.cc

@ -37,6 +37,7 @@ MAVLinkDecoder::MAVLinkDecoder(MAVLinkProtocol* protocol, QObject *parent) :
messageFilter.insert(MAVLINK_MSG_ID_DATA_STREAM, false); messageFilter.insert(MAVLINK_MSG_ID_DATA_STREAM, false);
messageFilter.insert(MAVLINK_MSG_ID_GPS_STATUS, false); messageFilter.insert(MAVLINK_MSG_ID_GPS_STATUS, false);
messageFilter.insert(MAVLINK_MSG_ID_RC_CHANNELS_RAW, false); messageFilter.insert(MAVLINK_MSG_ID_RC_CHANNELS_RAW, false);
messageFilter.insert(MAVLINK_MSG_ID_LOG_DATA, false);
#ifdef MAVLINK_MSG_ID_ENCAPSULATED_DATA #ifdef MAVLINK_MSG_ID_ENCAPSULATED_DATA
messageFilter.insert(MAVLINK_MSG_ID_ENCAPSULATED_DATA, false); messageFilter.insert(MAVLINK_MSG_ID_ENCAPSULATED_DATA, false);
#endif #endif

Loading…
Cancel
Save