29#include <etl/error_handler.h>
30#include <etl/string_stream.h>
31#include <etl/to_string.h>
33#include <zephyr/device.h>
34#include <zephyr/devicetree.h>
35#include <zephyr/drivers/uart.h>
36#include <zephyr/fs/fs.h>
37#include <zephyr/retention/retention.h>
38#include <zephyr/task_wdt/task_wdt.h>
50static const struct device *retention_memory_dev =
51 DEVICE_DT_GET(DT_CHOSEN(zephyr_retention_memory));
55#if DT_NODE_EXISTS(DT_ALIAS(uartlog))
56K_SEM_DEFINE(tx_done, 1, 1);
57static __aligned(32) uint8_t dma_buf[CONFIG_LOG_MAX_MSG_LEN];
60uart_callback(const struct device *dev, struct uart_event *evt,
void *user_data)
70 case UART_RX_BUF_RELEASED:
72 case UART_RX_BUF_REQUEST:
74 case UART_RX_DISABLED:
82static etl::string<CONFIG_LOG_MAX_MSG_LEN> log_str;
95 etl::string<CONFIG_LOG_MAX_MSG_LEN> msg;
96 etl::string_stream stream(msg);
97 stream <<
"SatNOGS-COMMS FW: " << sc::version::fw_major <<
"."
98 << sc::version::fw_minor <<
"." << sc::version::fw_patch
99 <<
", LIB: " << scl::version::lib_major <<
"."
100 << scl::version::lib_minor <<
"." << scl::version::lib_patch
101 <<
", HW: " << scl::version::hw_major <<
"." << scl::version::hw_minor
102 <<
"." << scl::version::hw_patch <<
" initialized";
188 log_unlocked(list, e);
201logger::log(std::initializer_list<target> list,
const std::exception &e)
205 log_unlocked(list, e);
218logger::log(std::initializer_list<target> list,
const etl::exception &e)
222 log_unlocked(list, e);
238 log_unlocked(list, msg);
255 LOG_ERR(
"Exception: %s", log_str.c_str());
267logger::rtt_push(
const etl::exception &e)
269 LOG_ERR(
"Exception: %s", e.what());
281logger::rtt_push(
const std::exception &e)
283 LOG_ERR(
"Exception: %s", e.what());
294logger::rtt_push(
const char *msg)
314 log_str.append(
"EXC: ");
316 e.to_string(log_str);
317 if (m_ring_buffer.full() ==
true) {
320 m_ring_buffer.push(
ring_buf_msg(t_src, t_posix, log_str));
331logger::ring_buffer_push(
const std::exception &e)
337 log_str.append(
"EXC: ");
339 log_str.append(e.what());
340 if (m_ring_buffer.full() ==
true) {
343 m_ring_buffer.push(
ring_buf_msg(t_src, t_posix, log_str));
354logger::ring_buffer_push(
const etl::exception &e)
360 log_str.append(
"EXC: ");
362 log_str.append(e.what());
363 if (m_ring_buffer.full() ==
true) {
366 m_ring_buffer.push(
ring_buf_msg(t_src, t_posix, log_str));
379logger::ring_buffer_push(
const char *msg)
385 log_str.append(
"LOG: ");
388 if (m_ring_buffer.full() ==
true) {
391 m_ring_buffer.push(
ring_buf_msg(t_src, t_posix, log_str));
411#if DT_NODE_EXISTS(DT_ALIAS(uartlog))
413 log_str.append(
"EXC: ");
414 log_str.append(e.what());
415 log_str.append(
"\r\n");
416 const struct device *uart_log = DEVICE_DT_GET(DT_ALIAS(uartlog));
421 if (k_sem_take(&tx_done, K_MSEC(400))) {
422 uart_tx_abort(uart_log);
425 memcpy(dma_buf,
reinterpret_cast<const uint8_t *
>(log_str.c_str()),
427 uart_tx(uart_log, dma_buf, log_str.size(), SYS_FOREVER_US);
443logger::uart_push(
const std::exception &e)
445#if DT_NODE_EXISTS(DT_ALIAS(uartlog))
447 log_str.append(
"EXC: ");
448 log_str.append(e.what());
449 const struct device *uart_log = DEVICE_DT_GET(DT_ALIAS(uartlog));
450 uart_tx(uart_log,
reinterpret_cast<const uint8_t *
>(log_str.c_str()),
451 log_str.size(), 100000);
467logger::uart_push(
const etl::exception &e)
469#if DT_NODE_EXISTS(DT_ALIAS(uartlog))
471 log_str.append(
"EXC: ");
472 log_str.append(e.what());
473 const struct device *uart_log = DEVICE_DT_GET(DT_ALIAS(uartlog));
474 uart_tx(uart_log,
reinterpret_cast<const uint8_t *
>(log_str.c_str()),
475 log_str.size(), 100000);
491logger::uart_push(
const char *msg)
493#if DT_NODE_EXISTS(DT_ALIAS(uartlog))
495 log_str.append(
"LOG: ");
497 log_str.append(
"\r\n");
498 const struct device *uart_log = DEVICE_DT_GET(DT_ALIAS(uartlog));
504 if (k_sem_take(&tx_done, K_MSEC(400))) {
505 uart_tx_abort(uart_log);
508 memcpy(dma_buf,
reinterpret_cast<const uint8_t *
>(log_str.c_str()),
510 uart_tx(uart_log, dma_buf, log_str.size(), SYS_FOREVER_US);
515logger::storage_push(
const std::exception &e)
525 storage.mkdir(m_logs_path);
532 etl::string_stream stream(log_str);
533 stream <<
"[" << etl::dec << (int)t_src <<
"," << etl::dec << t_posix
535 <<
"EXC: " << e.what() <<
"\r\n";
537 current_log_file(m_logs_path);
538 storage.write(m_logs_path, (
const uint8_t *)log_str.c_str(),
540 }
catch (lib::exception &e) {
546logger::storage_push(
const etl::exception &e)
556 storage.mkdir(m_logs_path);
563 etl::string_stream stream(log_str);
564 stream <<
"[" << etl::dec << (int)t_src <<
"," << etl::dec << t_posix
566 <<
"EXC: " << e.what() <<
"\r\n";
568 current_log_file(m_logs_path);
569 storage.write(m_logs_path, (
const uint8_t *)log_str.c_str(),
571 }
catch (lib::exception &e) {
592 storage.mkdir(m_logs_path);
599 etl::string_stream stream(log_str);
600 stream <<
"[" << etl::dec << (int)t_src <<
"," << etl::dec << t_posix
605 current_log_file(m_logs_path);
606 storage.write(m_logs_path, (
const uint8_t *)log_str.c_str(),
608 }
catch (lib::exception &e) {
614logger::storage_push(
const char *msg)
625 storage.mkdir(m_logs_path);
632 etl::string_stream stream(log_str);
633 stream <<
"[" << etl::dec << (int)t_src <<
"," << etl::dec << t_posix
635 <<
"LOG: " << msg <<
"\r\n";
636 current_log_file(m_logs_path);
637 storage.write(m_logs_path, (
const uint8_t *)log_str.c_str(),
639 }
catch (lib::exception &e) {
651logger::current_log_file(etl::istring &path)
654 etl::string_stream stream(m_logs_path);
658 auto tsrc = time.get(t);
663 uint32_t days = time.uptime() / (24 * 60 * 60 * 1000);
666 <<
"boot-" << boot_cnt <<
"-" << days <<
".log";
671 strftime(strt, 15,
"%Y-%m-%d", &t);
691 time_t start_posix = timeutil_timegm(&start);
692 time_t end_posix = timeutil_timegm(&end);
693 time_t day_posix = 24 * 60 * 60;
696 for (time_t t = start_posix; t <= end_posix; t += day_posix) {
700 etl::string_stream stream(m_logs_path);
701 stream <<
mcu_log_dir <<
"/" << tmp.tm_year <<
"-" << tmp.tm_mon <<
"-"
702 << tmp.tm_mday <<
".log";
728 CONFIG_BACKUP_SRAM_EXCEPTION_LOG_LEVEL) {
731 retention_clear(retention_memory_dev);
732 return retention_write(retention_memory_dev, 0U,
733 reinterpret_cast<const uint8_t *
>(log_str.c_str()),
734 CONFIG_LOG_MAX_MSG_LEN);
748logger::backup_sram_push(
const std::exception &e)
750 retention_clear(retention_memory_dev);
751 return retention_write(retention_memory_dev, 0U,
752 reinterpret_cast<const uint8_t *
>(e.what()),
753 CONFIG_LOG_MAX_MSG_LEN);
765logger::backup_sram_push(
const etl::exception &e)
767 retention_clear(retention_memory_dev);
768 return retention_write(retention_memory_dev, 0U,
769 reinterpret_cast<const uint8_t *
>(e.what()),
770 CONFIG_LOG_MAX_MSG_LEN);
776 return m_ring_buffer.size();
782 data = *(m_ring_buffer.crbegin() + index);
790etl::string<CONFIG_LOG_MAX_MSG_LEN>
793 if (retention_is_valid(retention_memory_dev) != 1) {
794 return "Data in BACKUP SRAM is not valid";
796 if (retention_read(retention_memory_dev, 0U,
798 CONFIG_LOG_MAX_MSG_LEN) != 0) {
799 return "Error while reading data from BACKUP SRAM device";
818 k_mutex_init(&m_mtx);
819#if DT_NODE_EXISTS(DT_ALIAS(uartlog))
820 const struct device *uart_log = DEVICE_DT_GET(DT_ALIAS(uartlog));
821 struct uart_config uart_cfg = {
822 .baudrate = CONFIG_LOG_UART_BAUDRATE,
823 .parity = UART_CFG_PARITY_NONE,
824 .stop_bits = UART_CFG_STOP_BITS_1,
825 .data_bits = UART_CFG_DATA_BITS_8,
826 .flow_ctrl = UART_CFG_FLOW_CTRL_NONE,
828 uart_rx_disable(uart_log);
829 uart_tx_abort(uart_log);
830 uart_configure(uart_log, &uart_cfg);
831 uart_callback_set(uart_log, uart_callback,
nullptr);
@ MINOR
Failure having minimal impact.
severity get_severity() const
Get error severity level as defined in FDIR.
void to_string(etl::string_stream &stream) const
Creates a string representation of the exception.
etl::string< CONFIG_LOG_MAX_MSG_LEN > get_latest_exception() const
Retrieves the latest exception message stored in BACKUP_SRAM.
size_t get_ring_buffer_size()
@ RING_BUFFER
In-memory ring buffer for storing recent log messages.
@ STORAGE
eMMC logging for persistent storage
@ UART
UART logging output.
@ RTT
Real-Time Transfer logging (Segger RTT).
void get_ring_buffer_log(ring_buf_msg &data, size_t index)
static constexpr const char * mcu_log_dir
void delete_storage_logs(struct tm &start, struct tm &end)
logger(logger const &)=delete
Disabled copy constructor to enforce singleton.
void boot()
Logs system initialization details to multiple targets (RTT, UART, and RING_BUFFER).
void log(std::initializer_list< target > list, const lib::exception &e)
Logs a satnogs::comms::lib::exception to a specified set of targets.
Implements a scoped lock utilizing the Zephyr mutex.
static settings & get_instance()
Get a singleton access to the settings subsystem.
bool enabled() const
Checks if the storage subsystem is enabled.
static storage & get_instance()
lib::emmc::dir get_dir() const
Get the direction of the eMMC.
void rm(const etl::istring &path)
Removes a file from the filesystem.
static time & get_instance()
time_src
Source of the reported time.
@ UPTIME
No RTC or GNSS time source. The uptime is used to track time.
@ GNSS_ONLY
No RTC installed, but there is time information from a GNSS fix.
LOG_MODULE_REGISTER(satnogscomms, CONFIG_LOG_DEFAULT_LEVEL)
etl::string< CONFIG_LOG_MAX_MSG_LEN > retentained_mem_str