2022-11-30 12:29:28 +00:00
|
|
|
#include "Log.h"
|
2022-11-30 16:12:06 +00:00
|
|
|
#include "arch/CPU.h"
|
2022-11-30 12:29:28 +00:00
|
|
|
#include "arch/Serial.h"
|
|
|
|
#include "arch/Timer.h"
|
|
|
|
#include "video/TextConsole.h"
|
2022-12-04 11:42:43 +00:00
|
|
|
#include <luna/Format.h>
|
2022-11-30 12:29:28 +00:00
|
|
|
|
|
|
|
static bool g_debug_enabled = true;
|
|
|
|
static bool g_serial_enabled = true;
|
|
|
|
static bool g_text_console_enabled = false;
|
|
|
|
|
|
|
|
static constexpr u32 BLACK = 0xff000000;
|
|
|
|
static constexpr u32 WHITE = 0xffffffff;
|
|
|
|
static constexpr u32 YELLOW = 0xffffff00;
|
|
|
|
static constexpr u32 RED = 0xffff0000;
|
|
|
|
|
2022-11-30 16:26:33 +00:00
|
|
|
static char log_level_letters[] = {'D', 'I', 'W', 'E'}; // D for debug, I for info, W for warning, E for error
|
|
|
|
static const char* ansi_color_codes_per_log_level[] = {"37", "37", "33", "31"}; // 37 is white, 33 yellow, 31 red
|
|
|
|
|
|
|
|
static Result<void> log_serial(LogLevel level, const char* format, va_list origin)
|
2022-11-30 12:29:28 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_copy(ap, origin);
|
|
|
|
|
2022-11-30 16:26:33 +00:00
|
|
|
TRY(Serial::printf("\x1b[%sm%c\x1b[0m ", ansi_color_codes_per_log_level[(int)level],
|
|
|
|
log_level_letters[(int)level]));
|
|
|
|
|
2022-11-30 12:29:28 +00:00
|
|
|
TRY(Serial::printf("[%6zu.%.6zu] ", Timer::ticks(), Timer::ticks_us() - (Timer::ticks() * 1000000)));
|
|
|
|
|
|
|
|
TRY(cstyle_format(
|
|
|
|
format,
|
|
|
|
[](char c, void*) -> Result<void> {
|
|
|
|
Serial::putchar(c);
|
|
|
|
return {};
|
|
|
|
},
|
|
|
|
nullptr, ap));
|
|
|
|
|
|
|
|
Serial::putchar('\n');
|
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
static Result<void> log_text_console(LogLevel level, const char* format, va_list origin)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_copy(ap, origin);
|
|
|
|
|
|
|
|
u32 original_foreground = TextConsole::foreground();
|
|
|
|
u32 original_background = TextConsole::background();
|
|
|
|
|
|
|
|
TextConsole::set_background(BLACK);
|
|
|
|
|
|
|
|
if (level == LogLevel::Warn) TextConsole::set_foreground(YELLOW);
|
|
|
|
else if (level == LogLevel::Error)
|
|
|
|
TextConsole::set_foreground(RED);
|
|
|
|
else
|
|
|
|
TextConsole::set_foreground(WHITE);
|
|
|
|
|
|
|
|
TRY(cstyle_format(
|
|
|
|
format,
|
|
|
|
[](char c, void*) -> Result<void> {
|
|
|
|
TextConsole::putchar(c);
|
|
|
|
return {};
|
|
|
|
},
|
|
|
|
nullptr, ap));
|
|
|
|
|
|
|
|
TextConsole::putchar('\n');
|
|
|
|
|
|
|
|
TextConsole::set_background(original_background);
|
|
|
|
|
|
|
|
TextConsole::set_foreground(original_foreground);
|
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<void> vlog(LogLevel level, const char* format, va_list ap)
|
|
|
|
{
|
|
|
|
if (!g_debug_enabled && level == LogLevel::Debug) return {};
|
|
|
|
|
|
|
|
if (g_serial_enabled) TRY(log_serial(level, format, ap));
|
|
|
|
if (g_text_console_enabled) TRY(log_text_console(level, format, ap));
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<void> log(LogLevel level, const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
|
|
|
|
|
|
TRY(vlog(level, format, ap));
|
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
void setup_log(bool enable_debug, bool enable_serial, bool enable_text_console)
|
|
|
|
{
|
|
|
|
g_debug_enabled = enable_debug;
|
|
|
|
g_serial_enabled = enable_serial;
|
|
|
|
g_text_console_enabled = enable_text_console;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool log_debug_enabled()
|
|
|
|
{
|
|
|
|
return g_debug_enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool log_serial_enabled()
|
|
|
|
{
|
|
|
|
return g_serial_enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool log_text_console_enabled()
|
|
|
|
{
|
|
|
|
return g_text_console_enabled;
|
2022-11-30 16:12:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool g_check_already_failed = false;
|
|
|
|
|
|
|
|
_noreturn bool __check_failed(const char* file, const char* line, const char* func, const char* expr)
|
|
|
|
{
|
|
|
|
if (!g_check_already_failed)
|
|
|
|
{ // Avoid endlessly failing when trying to report a failed check.
|
|
|
|
g_check_already_failed = true;
|
|
|
|
kerrorln("ERROR: Check failed at %s:%s, in %s: %s", file, line, func, expr);
|
|
|
|
}
|
|
|
|
CPU::efficient_halt();
|
2022-11-30 12:29:28 +00:00
|
|
|
}
|