Commit 9297cdf3 authored by Nate Weibley's avatar Nate Weibley

Different log download strategy. Break into chunks of 90 byte bins, finish chunks sequentially

parent 3565bfe3
...@@ -37,10 +37,50 @@ ...@@ -37,10 +37,50 @@
#define kTimeOutMilliseconds 500 #define kTimeOutMilliseconds 500
#define kGUIRateMilliseconds 17 #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_)
...@@ -276,18 +316,25 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui ...@@ -276,18 +316,25 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui
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;
uint32_t timeout_time = kTimeOutMilliseconds; uint32_t timeout_time = kTimeOutMilliseconds;
if(ofs <= _downloadData->entry->size()) { if(ofs <= _downloadData->entry->size()) {
// Check for a gap const uint32_t chunk = ofs / kChunkSize;
qint64 pos = _downloadData->file.pos(); if (chunk != _downloadData->current_chunk) {
if (pos != ofs) { qWarning() << "Ignored packet for out of order chunk" << chunk;
if (pos < ofs) { return;
// Mind the gap }
uint32_t gap = ofs - pos; const uint16_t bin = (ofs - chunk*kChunkSize) / MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN;
_downloadData->gaps[pos] = gap; 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 // Seek to correct position
if (!_downloadData->file.seek(ofs)) { if (!_downloadData->file.seek(ofs)) {
qWarning() << "Error while seeking log file offset"; qWarning() << "Error while seeking log file offset";
...@@ -295,17 +342,6 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui ...@@ -295,17 +342,6 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui
} }
} }
// Check for a gap collision
if (_downloadData->gaps.contains(ofs)) {
// The gap is being filled. Shrink it
const int32_t gap = _downloadData->gaps.take(ofs) - count;
if (gap > 0) {
_downloadData->gaps[ofs+count] = qMax(static_cast<uint32_t>(gap), _downloadData->gaps.value(ofs+count, 0));
} else {
timeout_time = 20;
}
}
//-- Write chunk to file //-- Write chunk to file
if(_downloadData->file.write((const char*)data, count)) { if(_downloadData->file.write((const char*)data, count)) {
_downloadData->written += count; _downloadData->written += count;
...@@ -325,6 +361,11 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui ...@@ -325,6 +361,11 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui
_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";
...@@ -337,12 +378,19 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui ...@@ -337,12 +378,19 @@ LogDownloadController::_logData(UASInterface* uas, uint32_t ofs, uint16_t id, ui
} }
} }
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
bool bool
LogDownloadController::_logComplete() LogDownloadController::_chunkComplete() const
{ {
return _downloadData->file.pos() == _downloadData->entry->size() && return _downloadData->chunkEquals(true);
_downloadData->gaps.count() == 0; }
//----------------------------------------------------------------------------------------
bool
LogDownloadController::_logComplete() const
{
return _chunkComplete() && (_downloadData->current_chunk+1) == _downloadData->numChunks();
} }
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
...@@ -353,7 +401,7 @@ LogDownloadController::_receivedAllData() ...@@ -353,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);
...@@ -367,6 +415,8 @@ LogDownloadController::_findMissingData() ...@@ -367,6 +415,8 @@ LogDownloadController::_findMissingData()
if (_logComplete()) { if (_logComplete()) {
_receivedAllData(); _receivedAllData();
return; return;
} else if (_chunkComplete()) {
_downloadData->advanceChunk();
} }
if(_retries++ > 2) { if(_retries++ > 2) {
...@@ -377,24 +427,23 @@ LogDownloadController::_findMissingData() ...@@ -377,24 +427,23 @@ LogDownloadController::_findMissingData()
return; return;
} }
const qint64 pos = _downloadData->file.pos(), uint16_t start = 0, end = 0;
size = _downloadData->entry->size(); const int size = _downloadData->chunk_table.size();
if (!_downloadData->gaps.isEmpty()) { for (; start < size; start++) {
auto keys = _downloadData->gaps.keys(); if (!_downloadData->chunk_table.testBit(start)) {
qSort(keys); break;
const uint32_t start = keys.first(); }
const uint32_t count = _downloadData->gaps.value(start);
_downloadData->file.seek(start);
//-- Request these log chunks again
_requestLogData(_downloadData->ID, start, count);
} else if (pos != size) {
// Request where we left off
_requestLogData(_downloadData->ID, pos, size - pos);
} else {
qWarning() << "Apparently we're missing data but can't figure out what. Giving up.";
_receivedAllData();
} }
for (end = start; end < size; end++) {
if (_downloadData->chunk_table.testBit(end)) {
break;
}
}
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);
} }
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
...@@ -547,8 +596,8 @@ LogDownloadController::_prepareLogDownload() ...@@ -547,8 +596,8 @@ 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 {
// Force ourselves to request the last few bytes if we have any gaps so we end cleanly _downloadData->current_chunk = 0;
_downloadData->gaps.insert(entry->size()-MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN, MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN); _downloadData->chunk_table = QBitArray(_downloadData->chunkBins(), false);
_downloadData->elapsed.start(); _downloadData->elapsed.start();
result = true; result = true;
} }
......
...@@ -122,18 +122,6 @@ private: ...@@ -122,18 +122,6 @@ private:
QString _status; QString _status;
}; };
//-----------------------------------------------------------------------------
struct LogDownloadData {
LogDownloadData(QGCLogEntry* entry);
QHash<uint32_t, uint32_t> gaps;
QFile file;
QString filename;
uint ID;
QGCLogEntry* entry;
uint written;
QElapsedTimer elapsed;
};
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class LogDownloadController : public FactPanelController class LogDownloadController : public FactPanelController
{ {
...@@ -170,7 +158,8 @@ private slots: ...@@ -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 ();
......
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