ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
logger_zephyr.cpp
Go to the documentation of this file.
1#ifdef USE_ZEPHYR
2
4#include "esphome/core/log.h"
5#include "logger.h"
6
7#include <zephyr/device.h>
8#include <zephyr/drivers/uart.h>
9#include <zephyr/sys/printk.h>
10#include <zephyr/usb/usb_device.h>
11#ifdef USE_LOGGER_EARLY_MESSAGE
13#endif
14
16
17__attribute__((weak)) void print_coredump() {}
18
19} // namespace esphome::zephyr_coredump
20
21namespace esphome::logger {
22
23__attribute__((section(".noinit"))) struct {
24 uint32_t magic;
25 uint32_t reason;
28#if defined(CONFIG_THREAD_NAME)
29 char thread[CONFIG_THREAD_MAX_NAME_LEN];
30#endif
31} crash_buf; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
32
33static const char *const TAG = "logger";
34
35#ifdef USE_LOGGER_UART_SELECTION_USB_CDC
37 if (this->uart_ != UART_SELECTION_USB_CDC || this->uart_dev_ == nullptr) {
38 return;
39 }
40 static bool opened = false;
41 uint32_t dtr = 0;
42 uart_line_ctrl_get(this->uart_dev_, UART_LINE_CTRL_DTR, &dtr);
43
44 /* Poll if the DTR flag was set, optional */
45 if (opened == dtr) {
46 return;
47 }
48
49 if (!opened) {
51 }
52 opened = !opened;
53}
54#endif
55
56void Logger::pre_setup() {
57 if (this->baud_rate_ > 0) {
58 static const struct device *uart_dev = nullptr;
59 switch (this->uart_) {
61 uart_dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(uart0));
62 break;
64 uart_dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(uart1));
65 break;
66#ifdef USE_LOGGER_USB_CDC
68#ifdef CONFIG_USB_DEVICE_STACK
69 uart_dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(cdc_acm_uart0));
70 if (device_is_ready(uart_dev)) {
71 usb_enable(nullptr);
72 }
73#endif
74 break;
75#endif
76 }
77 if (device_is_ready(uart_dev)) {
78 this->uart_dev_ = uart_dev;
79#if defined(USE_LOGGER_WAIT_FOR_CDC) && defined(USE_LOGGER_UART_SELECTION_USB_CDC)
80 uint32_t dtr = 0;
81 int32_t count = (10 * 100); // wait 10 sec for USB CDC to have early logs
82 while (dtr == 0 && count-- > 0) {
83 uart_line_ctrl_get(this->uart_dev_, UART_LINE_CTRL_DTR, &dtr);
84 delay(10);
86 }
87#endif
88 }
89 }
90 global_logger = this;
91 ESP_LOGI(TAG, "Log initialized");
92#ifdef USE_LOGGER_EARLY_MESSAGE
93 char reason_buffer[zephyr::RESET_REASON_BUFFER_SIZE];
94 const char *reset_reason = zephyr::get_reset_reason(std::span<char, zephyr::RESET_REASON_BUFFER_SIZE>(reason_buffer));
95 ESP_LOGI(TAG, "Reset reason: %s", reset_reason);
97 zephyr_coredump::print_coredump();
98#endif
99}
100
101void HOT Logger::write_msg_(const char *msg, uint16_t len) {
102 // Single write with newline already in buffer (added by caller)
103#ifdef CONFIG_PRINTK
104 // Requires the debug component and an active SWD connection.
105 // It is used for pyocd rtt -t nrf52840
106 printk("%.*s", static_cast<int>(len), msg);
107#endif
108 if (this->uart_dev_ == nullptr) {
109 return;
110 }
111 for (uint16_t i = 0; i < len; ++i) {
112 uart_poll_out(this->uart_dev_, msg[i]);
113 }
114}
115
116const LogString *Logger::get_uart_selection_() {
117 switch (this->uart_) {
119 return LOG_STR("UART0");
121 return LOG_STR("UART1");
122#ifdef USE_LOGGER_USB_CDC
124 return LOG_STR("USB_CDC");
125#endif
126 default:
127 return LOG_STR("UNKNOWN");
128 }
129}
130
131static const uint8_t REASON_BUF_SIZE = 32;
132
133static const char *reason_to_str(unsigned int reason, char *buf) {
134 switch (reason) {
135 case K_ERR_CPU_EXCEPTION:
136 return "CPU exception";
137 case K_ERR_SPURIOUS_IRQ:
138 return "Unhandled interrupt";
139 case K_ERR_STACK_CHK_FAIL:
140 return "Stack overflow";
141 case K_ERR_KERNEL_OOPS:
142 return "Kernel oops";
143 case K_ERR_KERNEL_PANIC:
144 return "Kernel panic";
145 default:
146 snprintf(buf, REASON_BUF_SIZE, "Unknown error (%u)", reason);
147 return buf;
148 }
149}
150
152 ESP_LOGD(TAG, "Crash buffer address %p", &crash_buf);
153 if (crash_buf.magic == App.get_config_hash()) {
154 char reason_buf[REASON_BUF_SIZE];
155 ESP_LOGE(TAG, "Last crash:");
156 ESP_LOGE(TAG, "Reason=%s PC=0x%08x LR=0x%08x", reason_to_str(crash_buf.reason, reason_buf), crash_buf.pc,
157 crash_buf.lr);
158#if defined(CONFIG_THREAD_NAME)
159 ESP_LOGE(TAG, "Thread: %s", crash_buf.thread);
160#endif
161 int32_t count = (2 * 100); // wait 2 sec to give a chance to print crash
162 while (count-- > 0) {
163 delay(10);
165 }
166 }
167}
168
169void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf) {
170 crash_buf.magic = App.get_config_hash();
171 crash_buf.reason = reason;
172 if (esf) {
173 crash_buf.pc = esf->basic.pc;
174 crash_buf.lr = esf->basic.lr;
175 }
176#if defined(CONFIG_THREAD_NAME)
177 auto thread = k_current_get();
178 const char *name = k_thread_name_get(thread);
179 if (name) {
180 strncpy(crash_buf.thread, name, sizeof(crash_buf.thread) - 1);
181 crash_buf.thread[sizeof(crash_buf.thread) - 1] = '\0';
182 } else {
183 crash_buf.thread[0] = '\0';
184 }
185#endif
186 arch_restart();
187}
188
189} // namespace esphome::logger
190
191extern "C" {
192
193void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf) {
195}
196}
197
198#endif
uint32_t get_config_hash()
Get the config hash as a 32-bit integer.
UARTSelection uart_
Definition logger.h:355
void write_msg_(const char *msg, uint16_t len)
Definition logger_esp32.h:9
const LogString * get_uart_selection_()
void pre_setup()
Set up this component.
const device * uart_dev_
Definition logger.h:321
struct @65::@66 __attribute__
Wake the main loop task from an ISR. ISR-safe.
Definition main_task.h:32
void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf)
void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf)
@ UART_SELECTION_USB_CDC
Definition logger.h:116
@ UART_SELECTION_UART0
Definition logger.h:107
@ UART_SELECTION_UART1
Definition logger.h:111
Logger * global_logger
Definition logger.cpp:275
const char * get_reset_reason(std::span< char, RESET_REASON_BUFFER_SIZE > buffer)
const void size_t len
Definition hal.h:64
void arch_feed_wdt()
Definition hal.cpp:53
void HOT delay(uint32_t ms)
Definition hal.cpp:85
void arch_restart()
Definition hal.cpp:39
Application App
Global storage of Application pointer - only one Application can exist.
static void uint32_t
uint32_t lr
uint32_t pc