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