AP_Logger: fixed log listing with gap, and EKF error on log list

this fixes two issues:

The first issue that if we are missing a log file in the middle of the
list then it was not possible to download recent logs, as we get the
incorrect value for total number of logs. This happened for me with
107 logs, with log62 missing from the microSD. It would only show 45
available logs, so the most recent logs could not be downloaded.

The second issue is that get_num_logs() was very slow if there were a
lot of log files in a directory. This would cause EKF errors and ESC
resets. Using a opendir/readdir loop is much faster (approx 10x faster
in my testing with 107 logs on a MatekH743).
This commit is contained in:
Andrew Tridgell 2022-04-18 10:25:16 +10:00
parent 1444aeadf0
commit f9765a98ff
2 changed files with 52 additions and 27 deletions

View File

@ -201,6 +201,29 @@ int64_t AP_Logger_File::disk_space()
return AP::FS().disk_space(_log_directory);
}
/*
convert a dirent to a log number
*/
bool AP_Logger_File::dirent_to_log_num(const dirent *de, uint16_t &log_num) const
{
uint8_t length = strlen(de->d_name);
if (length < 5) {
return false;
}
if (strncmp(&de->d_name[length-4], ".BIN", 4) != 0) {
// doesn't end in .BIN
return false;
}
uint16_t thisnum = strtoul(de->d_name, nullptr, 10);
if (thisnum > MAX_LOG_FILES) {
return false;
}
log_num = thisnum;
return true;
}
// find_oldest_log - find oldest log in _log_directory
// returns 0 if no log was found
uint16_t AP_Logger_File::find_oldest_log()
@ -230,19 +253,9 @@ uint16_t AP_Logger_File::find_oldest_log()
EXPECT_DELAY_MS(3000);
for (struct dirent *de=AP::FS().readdir(d); de; de=AP::FS().readdir(d)) {
EXPECT_DELAY_MS(3000);
uint8_t length = strlen(de->d_name);
if (length < 5) {
// not long enough for \d+[.]BIN
continue;
}
if (strncmp(&de->d_name[length-4], ".BIN", 4) != 0) {
// doesn't end in .BIN
continue;
}
uint16_t thisnum = strtoul(de->d_name, nullptr, 10);
if (thisnum > MAX_LOG_FILES) {
// ignore files above our official maximum...
uint16_t thisnum;
if (!dirent_to_log_num(de, thisnum)) {
// not a log filename
continue;
}
if (current_oldest_log == 0) {
@ -661,29 +674,39 @@ void AP_Logger_File::get_log_info(const uint16_t list_entry, uint32_t &size, uin
}
/*
get the number of logs - note that the log numbers must be consecutive
*/
uint16_t AP_Logger_File::get_num_logs()
{
uint16_t ret = 0;
auto *d = AP::FS().opendir(_log_directory);
if (d == nullptr) {
return 0;
}
uint16_t high = find_last_log();
uint16_t i;
for (i=high; i>0; i--) {
if (! log_exists(i)) {
break;
uint16_t ret = high;
uint16_t smallest = high;
uint16_t smallest_above_last = 0;
EXPECT_DELAY_MS(2000);
for (struct dirent *de=AP::FS().readdir(d); de; de=AP::FS().readdir(d)) {
EXPECT_DELAY_MS(100);
uint16_t thisnum;
if (!dirent_to_log_num(de, thisnum)) {
// not a log filename
continue;
}
ret++;
}
if (i == 0) {
for (i=MAX_LOG_FILES; i>high; i--) {
if (! log_exists(i)) {
break;
}
ret++;
smallest = MIN(smallest, thisnum);
if (thisnum > high && (smallest_above_last != 0 || thisnum < smallest_above_last)) {
smallest_above_last = thisnum;
}
}
AP::FS().closedir(d);
if (smallest_above_last != 0) {
// we have wrapped, add in the logs with high numbers
ret += (MAX_LOG_FILES - smallest_above_last) + 1;
}
return ret;
}

View File

@ -100,6 +100,8 @@ private:
bool file_exists(const char *filename) const;
bool log_exists(const uint16_t lognum) const;
bool dirent_to_log_num(const dirent *de, uint16_t &log_num) const;
// write buffer
ByteBuffer _writebuf{0};
const uint16_t _writebuf_chunk = HAL_LOGGER_WRITE_CHUNK_SIZE;