#ifndef FSFW_EXAMPLE_HOSTED_TESTFMT_H #define FSFW_EXAMPLE_HOSTED_TESTFMT_H #include #include #include #include #include #include #include "fsfw/ipc/MutexFactory.h" #include "fsfw/ipc/MutexGuard.h" #include "fsfw/ipc/MutexIF.h" #include "fsfw/timemanager/Clock.h" #define __FILENAME_REL__ (((const char *)__FILE__ + SOURCE_PATH_SIZE)) #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) void fmtTests(); namespace sif { static std::array PRINT_BUF = {}; static const char INFO_PREFIX[] = "INFO"; static const char DEBUG_PREFIX[] = "DEBUG"; static const char WARNING_PREFIX[] = "WARNING"; static const char ERROR_PREFIX[] = "ERROR"; enum class LogLevel : unsigned int { DEBUG = 0, INFO = 1, WARNING = 2, ERROR = 3 }; static const char *PREFIX_ARR[4] = {DEBUG_PREFIX, INFO_PREFIX, WARNING_PREFIX, ERROR_PREFIX}; static const std::array LOG_COLOR_ARR = { fmt::color::deep_sky_blue, fmt::color::forest_green, fmt::color::orange_red, fmt::color::red}; static MutexIF *PRINT_MUTEX = MutexFactory::instance()->createMutex(); static size_t writeTypePrefix(LogLevel level) { auto idx = static_cast(level); const auto result = fmt::format_to_n(PRINT_BUF.begin(), PRINT_BUF.size() - 1, fmt::runtime(fmt::format(fg(LOG_COLOR_ARR[idx]), PREFIX_ARR[idx]))); return result.size; } template size_t logTraced(LogLevel level, const char *file, unsigned int line, bool timed, fmt::format_string fmt, T &&...args) noexcept { try { MutexGuard mg(PRINT_MUTEX); size_t bufPos = writeTypePrefix(level); auto currentIter = PRINT_BUF.begin() + bufPos; if (timed) { Clock::TimeOfDay_t logTime; Clock::getDateAndTime(&logTime); const auto result = fmt::format_to_n(currentIter, PRINT_BUF.size() - 1 - bufPos, " | {}[l.{}] | {:02}:{:02}:{:02}.{:03} | {}", file, line, logTime.hour, logTime.minute, logTime.second, logTime.usecond / 1000, fmt::format(fmt, args...)); *result.out = '\0'; bufPos += result.size; } else { const auto result = fmt::format_to_n(currentIter, PRINT_BUF.size() - 1 - bufPos, " | {}[l.{}] | {}", file, line, fmt::format(fmt, args...)); *result.out = '\0'; bufPos += result.size; } fmt::print(fmt::runtime(PRINT_BUF.data())); return bufPos; } catch (const fmt::v8::format_error &e) { fmt::print("Printing failed with error: {}\n", e.what()); return 0; } } template size_t log(LogLevel level, bool timed, fmt::format_string fmt, T &&...args) noexcept { try { MutexGuard mg(PRINT_MUTEX); size_t bufPos = writeTypePrefix(level); auto currentIter = PRINT_BUF.begin() + bufPos; if (timed) { Clock::TimeOfDay_t logTime; Clock::getDateAndTime(&logTime); const auto result = fmt::format_to_n( currentIter, PRINT_BUF.size() - bufPos, " | {:02}:{:02}:{:02}.{:03} | {}", logTime.hour, logTime.minute, logTime.second, logTime.usecond / 1000, fmt::format(fmt, args...)); bufPos += result.size; } fmt::print(fmt::runtime(PRINT_BUF.data())); return bufPos; } catch (const fmt::v8::format_error &e) { fmt::print("Printing failed with error: {}\n", e.what()); return 0; } } template void fdebug(const char *file, unsigned int line, fmt::format_string fmt, T &&...args) noexcept { logTraced(LogLevel::DEBUG, file, line, false, fmt, args...); } template void fdebug_t(const char *file, unsigned int line, fmt::format_string fmt, T &&...args) noexcept { logTraced(LogLevel::DEBUG, file, line, true, fmt, args...); } template void finfo_t(fmt::format_string fmt, T &&...args) { log(LogLevel::INFO, true, fmt, args...); } template void finfo(fmt::format_string fmt, T &&...args) { log(LogLevel::INFO, false, fmt, args...); } template void fwarning(const char *file, unsigned int line, fmt::format_string fmt, T &&...args) { logTraced(LogLevel::WARNING, file, line, false, fmt, args...); } template void fwarning_t(const char *file, unsigned int line, fmt::format_string fmt, T &&...args) { logTraced(LogLevel::WARNING, file, line, true, fmt, args...); } template void ferror(const char *file, unsigned int line, fmt::format_string fmt, T &&...args) { logTraced(LogLevel::ERROR, file, line, false, fmt, args...); } template void ferror_t(const char *file, unsigned int line, fmt::format_string fmt, T &&...args) { logTraced(LogLevel::ERROR, file, line, true, fmt, args...); } } // namespace sif #define FSFW_LOGI(format, ...) finfo(FMT_STRING(format), __VA_ARGS__) #define FSFW_LOGIT(format, ...) finfo_t(FMT_STRING(format), __VA_ARGS__) #define FSFW_LOGD(format, ...) sif::fdebug(__FILENAME__, __LINE__, FMT_STRING(format), __VA_ARGS__) #define FSFW_LOGDT(format, ...) fdebug_t(__FILENAME__, __LINE__, FMT_STRING(format), __VA_ARGS__) #define FSFW_LOGW(format, ...) fdebug(__FILENAME__, __LINE__, FMT_STRING(format), __VA_ARGS__) #define FSFW_LOGWT(format, ...) fdebug_t(__FILENAME__, __LINE__, FMT_STRING(format), __VA_ARGS__) #define FSFW_LOGE(format, ...) fdebug(__FILENAME__, __LINE__, FMT_STRING(format), __VA_ARGS__) #define FSFW_LOGET(format, ...) fdebug_t(__FILENAME__, __LINE__, FMT_STRING(format), __VA_ARGS__) #endif // FSFW_EXAMPLE_HOSTED_TESTFMT_H