Logging Updates (#978)

* log_file ensures directory exists
* Fix audio timestamp path
* Fix auto inc, add subfolder for recordings
* Fix auto inc and support subfolder
This commit is contained in:
Kyle Reed 2023-05-12 11:08:07 -07:00 committed by GitHub
parent 8b395239d2
commit a8cdde7bea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 132 additions and 62 deletions

View File

@ -98,10 +98,9 @@ ACARSAppView::ACARSAppView(NavigationView& nav) {
logging = v;
};
make_new_directory(LOG_ROOT_DIR);
logger = std::make_unique<ACARSLogger>();
if (logger)
logger->append( LOG_ROOT_DIR "/ACARS.TXT" );
logger->append(LOG_ROOT_DIR "/ACARS.TXT");
}
ACARSAppView::~ACARSAppView() {

View File

@ -397,7 +397,6 @@ AISAppView::AISAppView(NavigationView& nav) : nav_ { nav } {
this->on_show_list();
};
make_new_directory(LOG_ROOT_DIR);
logger = std::make_unique<AISLogger>();
if( logger ) {
logger->append( LOG_ROOT_DIR "/AIS.TXT" );

View File

@ -232,7 +232,7 @@ private:
RecordView record_view {
{ 0 * 8, 2 * 16, 30 * 8, 1 * 16 },
u"AUD",
u"AUD", u"AUDIO",
RecordView::FileType::WAV,
4096,
4

View File

@ -108,7 +108,7 @@ private:
RecordView record_view {
{ 0 * 8, 2 * 16, 30 * 8, 1 * 16 },
u"BBD_????", RecordView::FileType::RawS16, 16384, 3
u"BBD_????.*", u"CAPTURES", RecordView::FileType::RawS16, 16384, 3
};
spectrum::WaterfallWidget waterfall { };

View File

@ -130,7 +130,6 @@ ERTAppView::ERTAppView(NavigationView&) {
static_cast<int8_t>(receiver_model.vga()),
}); */
make_new_directory(LOG_ROOT_DIR);
logger = std::make_unique<ERTLogger>();
if( logger ) {
logger->append( LOG_ROOT_DIR "/ERT.TXT" );

View File

@ -129,10 +129,9 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
ignore_address /= 10;
}
make_new_directory(LOG_ROOT_DIR);
logger = std::make_unique<POCSAGLogger>();
if (logger)
logger->append( LOG_ROOT_DIR "/POCSAG.TXT" );
logger->append(LOG_ROOT_DIR "/POCSAG.TXT");
audio::output::start();
audio::output::unmute();

View File

@ -194,7 +194,6 @@ TPMSAppView::TPMSAppView(NavigationView&) {
options_temperature.set_selected_index(0, true);
make_new_directory(LOG_ROOT_DIR);
logger = std::make_unique<TPMSLogger>();
if( logger ) {
logger->append( LOG_ROOT_DIR "/TPMS.TXT" );

View File

@ -117,8 +117,6 @@ ADSBRxAircraftDetailsView::ADSBRxAircraftDetailsView(
std::unique_ptr<ADSBLogger> logger { };
make_new_directory(LOG_ROOT_DIR);
icao_code = to_string_hex(entry_copy.ICAO_address, 6);
text_icao_address.set(to_string_hex(entry_copy.ICAO_address, 6));

View File

@ -107,10 +107,9 @@ AFSKRxView::AFSKRxView(NavigationView& nav) {
nav.push<ModemSetupView>();
};
make_new_directory(LOG_ROOT_DIR);
logger = std::make_unique<AFSKLogger>();
if (logger)
logger->append( LOG_ROOT_DIR "/AFSK.TXT" );
logger->append(LOG_ROOT_DIR "/AFSK.TXT");
// Auto-configure modem for LCR RX (will be removed later)
baseband::set_afsk(persistent_memory::modem_baudrate(), 8, 0, false);

View File

@ -141,10 +141,9 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect) : View(parent_rect
options_region.set_selected_index(0, true);
make_new_directory(LOG_ROOT_DIR);
logger = std::make_unique<APRSLogger>();
if (logger)
logger->append( LOG_ROOT_DIR "/APRS.TXT" );
logger->append(LOG_ROOT_DIR "/APRS.TXT");
baseband::set_aprs(1200);

View File

@ -235,7 +235,7 @@ private:
// DEBUG
RecordView record_view {
{ 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
u"AFS_????", RecordView::FileType::WAV, 4096, 4
u"AFS_????.WAV", u"APRS", RecordView::FileType::WAV, 4096, 4
};
Console console {

View File

@ -42,8 +42,7 @@ bool is_hidden_file(const fs::path& path) {
// Gets a truncated name from a path for display.
std::string truncate(const fs::path& path, size_t max_length) {
auto name = path.string();
return name.length() <= max_length ? name : name.substr(0, max_length);
return ::truncate(path.string(), max_length);
}
// Gets a human readable file size string.

View File

@ -133,7 +133,6 @@ SondeView::SondeView(NavigationView& nav) {
999); //set a dummy heading out of range to draw a cross...probably not ideal?
};
make_new_directory(LOG_ROOT_DIR);
logger = std::make_unique<SondeLogger>();
if (logger)
logger->append( LOG_ROOT_DIR "/SONDE.TXT" );

View File

@ -79,7 +79,6 @@ TestView::TestView(NavigationView& nav) {
cal_value = raw_alt - 0x80;
};
logger = std::make_unique<TestLogger>();
if (logger)
logger->append("saucepan.txt");

View File

@ -124,50 +124,85 @@ Optional<File::Error> File::sync() {
}
}
static std::filesystem::path find_last_file_matching_pattern(const std::filesystem::path& pattern) {
std::filesystem::path last_match;
for(const auto& entry : std::filesystem::directory_iterator(u"", pattern)) {
if( std::filesystem::is_regular_file(entry.status()) ) {
/* Range used for filename matching.
* Start and end are inclusive positions of "???" */
struct pattern_range {
size_t start;
size_t end;
};
/* Finds the last file matching the specified pattern that
* can be automatically incremented (digits in pattern).
* NB: assumes a patten with contiguous '?' like "FOO_???.txt". */
static std::filesystem::path find_last_ordinal_match(
const std::filesystem::path& folder,
const std::filesystem::path& pattern,
pattern_range range
) {
auto last_match = std::filesystem::path();
auto can_increment = [range](const auto& path) {
for (auto i = range.start; i <= range.end; ++i)
if (!isdigit(path.native()[i]))
return false;
return true;
};
for (const auto& entry : std::filesystem::directory_iterator(folder, pattern)) {
if (std::filesystem::is_regular_file(entry.status()) && can_increment(entry.path())) {
const auto& match = entry.path();
if( match > last_match ) {
last_match = match;
}
}
}
return last_match;
}
static std::filesystem::path increment_filename_stem_ordinal(std::filesystem::path path) {
auto t = path.replace_extension().native();
auto it = t.rbegin();
/* Given a file path like "FOO_0001.txt" increment it to "FOO_0002.txt". */
static std::filesystem::path increment_filename_ordinal(
const std::filesystem::path& path, pattern_range range
) {
auto name = path.filename().native();
// Increment decimal number before the extension.
for(; it != t.rend(); ++it) {
const auto c = *it;
if( c < '0' ) {
for (auto i = range.end; i >= range.start; --i) {
auto& c = name[i];
// Not a digit or would overflow the counter.
if (c < u'0' || c > u'9' || (c == u'9' && i == range.start))
return { };
} else if( c < '9' ) {
*it += 1;
if (c == u'9')
c = '0';
else {
c++;
break;
} else if( c == '9' ) {
*it = '0';
} else {
return { };
}
}
return t;
return { name };
}
std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_pattern) {
const auto next_filename = find_last_file_matching_pattern(filename_pattern.replace_extension(u".*"));
if( next_filename.empty() ) {
auto pattern_s = filename_pattern.replace_extension().native();
std::replace(std::begin(pattern_s), std::end(pattern_s), '?', '0');
return pattern_s;
} else {
return increment_filename_stem_ordinal(next_filename);
std::filesystem::path next_filename_matching_pattern(const std::filesystem::path& filename_pattern) {
auto path = filename_pattern.parent_path();
auto pattern = filename_pattern.filename();
auto range = pattern_range {
pattern.native().find_first_of(u'?'),
pattern.native().find_last_of(u'?')
};
const auto match = find_last_ordinal_match(path, pattern, range);
if (match.empty()) {
auto pattern_str = pattern.native();
for (auto i = range.start; i <= range.end; ++i)
pattern_str[i] = u'0';
return path / pattern_str;
}
auto next_name = increment_filename_ordinal(match, range);
return next_name.empty() ? next_name : path / next_name;
}
std::vector<std::filesystem::path> scan_root_files(const std::filesystem::path& directory,
@ -214,7 +249,7 @@ std::filesystem::filesystem_error copy_file(
) {
File src;
File dst;
constexpr size_t buffer_size = 512;
constexpr size_t buffer_size = 128;
uint8_t buffer[buffer_size];
auto error = src.open(file_path);
@ -261,6 +296,19 @@ std::filesystem::filesystem_error make_new_directory(
return { f_mkdir(reinterpret_cast<const TCHAR*>(dir_path.c_str())) };
}
std::filesystem::filesystem_error ensure_directory(
const std::filesystem::path& dir_path
) {
if (dir_path.empty() || std::filesystem::file_exists(dir_path))
return { };
auto result = ensure_directory(dir_path.parent_path());
if (result.code())
return result;
return make_new_directory(dir_path);
}
namespace std {
namespace filesystem {
@ -383,8 +431,10 @@ directory_iterator::directory_iterator(
) : pattern { wild }
{
impl = std::make_shared<Impl>();
const auto result = f_findfirst(&impl->dir, &impl->filinfo, reinterpret_cast<const TCHAR*>(path.c_str()), reinterpret_cast<const TCHAR*>(pattern.c_str()));
if( result != FR_OK || impl->filinfo.fname[0] == (TCHAR)'\0') {
const auto result = f_findfirst(&impl->dir, &impl->filinfo,
reinterpret_cast<const TCHAR*>(path.c_str()),
reinterpret_cast<const TCHAR*>(pattern.c_str()));
if (result != FR_OK || impl->filinfo.fname[0] == (TCHAR)'\0') {
impl.reset();
// TODO: Throw exception if/when I enable exceptions...
}

View File

@ -59,6 +59,10 @@ struct filesystem_error {
std::string what() const;
bool ok() const {
return err == FR_OK;
}
private:
uint32_t err { FR_OK };
};
@ -258,12 +262,17 @@ std::filesystem::filesystem_error copy_file(const std::filesystem::path& file_pa
FATTimestamp file_created_date(const std::filesystem::path& file_path);
std::filesystem::filesystem_error make_new_file(const std::filesystem::path& file_path);
std::filesystem::filesystem_error make_new_directory(const std::filesystem::path& dir_path);
std::filesystem::filesystem_error ensure_directory(const std::filesystem::path& dir_path);
std::vector<std::filesystem::path> scan_root_files(const std::filesystem::path& directory, const std::filesystem::path& extension);
std::vector<std::filesystem::path> scan_root_directories(const std::filesystem::path& directory);
/* Gets an auto incrementing filename. */
std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_stem_pattern);
/* Gets an auto incrementing filename stem.
* Pattern should be like "FOO_???.txt" where ??? will be replaced by digits.
* Pattern may also contain a folder path like "LOGS/FOO_???.txt".
* Pattern '?' must be contiguous (bad: "FOO?_??")
* Returns empty path if a filename could not be created. */
std::filesystem::path next_filename_matching_pattern(const std::filesystem::path& pattern);
/* Values added to FatFs FRESULT enum, values outside the FRESULT data type */
static_assert(sizeof(FIL::err) == 1, "FatFs FIL::err size not expected.");

View File

@ -35,6 +35,10 @@ using namespace lpc43xx;
class LogFile {
public:
Optional<File::Error> append(const std::filesystem::path& filename) {
auto result = ensure_directory(filename.parent_path());
if (result.code())
return { result };
return file.append(filename);
}

View File

@ -256,8 +256,17 @@ double get_decimals(double num, int16_t mult, bool round) {
return intnum;
}
std::string trimr(std::string str)
{
std::string trim(const std::string& str) {
auto first = str.find_first_not_of(' ');
auto last = str.find_last_not_of(' ');
return str.substr(first, last - first);
}
std::string trimr(std::string str) {
size_t last = str.find_last_not_of(' ');
return (last!=std::string::npos) ? str.substr(0, last+1) : ""; // Remove the trailing spaces
}
std::string truncate(const std::string& str, size_t length) {
return str.length() <= length ? str : str.substr(0, length);
}

View File

@ -59,6 +59,8 @@ std::string to_string_FAT_timestamp(const FATTimestamp& timestamp);
std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precision);
double get_decimals(double num, int16_t mult, bool round = false); //euquiq added
std::string trim(const std::string& str); // Remove whitespace at ends.
std::string trimr(std::string str); // Remove trailing spaces
std::string truncate(const std::string& str, size_t length);
#endif/*__STRING_FORMAT_H__*/

View File

@ -367,13 +367,15 @@ void SystemStatusView::on_bias_tee() {
}*/
void SystemStatusView::on_camera() {
auto path = next_filename_stem_matching_pattern(u"SCR_????");
ensure_directory("SCREENSHOTS");
auto path = next_filename_matching_pattern(u"SCREENSHOTS/SCR_????.PNG");
if( path.empty() ) {
return;
}
PNGWriter png;
auto create_error = png.create(path.replace_extension(u".PNG"));
auto create_error = png.create(path);
if( create_error.is_valid() ) {
return;
}

View File

@ -55,16 +55,19 @@ namespace ui {
RecordView::RecordView(
const Rect parent_rect,
std::filesystem::path filename_stem_pattern,
const std::filesystem::path& filename_stem_pattern,
const std::filesystem::path& folder,
const FileType file_type,
const size_t write_size,
const size_t buffer_count
) : View { parent_rect },
filename_stem_pattern { filename_stem_pattern },
folder { folder },
file_type { file_type },
write_size { write_size },
buffer_count { buffer_count }
{
ensure_directory(folder);
add_children({
&rect_background,
//&button_pitch_rssi,
@ -154,7 +157,6 @@ void RecordView::start() {
return;
}
std::filesystem::path base_path;
if(filename_date_frequency) {
rtcGetTime(&RTCD1, &datetime);
@ -167,9 +169,11 @@ void RecordView::start() {
to_string_dec_uint(datetime.minute()) +
to_string_dec_uint(datetime.second());
base_path = filename_stem_pattern.string() + "_" + date_time + "_" + to_string_freq(receiver_model.tuning_frequency()) + "Hz";
base_path = filename_stem_pattern.string() + "_" + date_time + "_" +
trim(to_string_freq(receiver_model.tuning_frequency())) + "Hz";
base_path = folder / base_path;
} else {
base_path = next_filename_stem_matching_pattern(filename_stem_pattern);
base_path = next_filename_matching_pattern(folder / filename_stem_pattern);
}
if( base_path.empty() ) {
@ -217,7 +221,7 @@ void RecordView::start() {
};
if( writer ) {
text_record_filename.set(base_path.replace_extension().string());
text_record_filename.set(truncate(base_path.filename().string(), 8));
button_record.set_bitmap(&bitmap_stop);
capture_thread = std::make_unique<CaptureThread>(
std::move(writer),
@ -275,7 +279,7 @@ void RecordView::on_tick_second() {
void RecordView::update_status_display() {
if( is_active() ) {
const auto dropped_percent = std::min(99U, capture_thread->state().dropped_percent());
const auto s = to_string_dec_uint(dropped_percent, 2, ' ') + "\%";
const auto s = to_string_dec_uint(dropped_percent, 2, ' ') + "%";
text_record_dropped.set(s);
}

View File

@ -46,7 +46,8 @@ public:
RecordView(
const Rect parent_rect,
std::filesystem::path filename_stem_pattern,
const std::filesystem::path& filename_stem_pattern,
const std::filesystem::path& folder,
FileType file_type,
const size_t write_size,
const size_t buffer_count
@ -83,6 +84,7 @@ private:
rtc::RTC datetime { };
const std::filesystem::path filename_stem_pattern;
const std::filesystem::path folder;
const FileType file_type;
const size_t write_size;
const size_t buffer_count;