ESPHome 2026.3.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;
26 uint32_t pc;
27 uint32_t lr;
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 uart_dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(cdc_acm_uart0));
69 if (device_is_ready(uart_dev)) {
70 usb_enable(nullptr);
71 }
72 break;
73#endif
74 }
75 if (!device_is_ready(uart_dev)) {
76 ESP_LOGE(TAG, "%s is not ready.", LOG_STR_ARG(get_uart_selection_()));
77 } else {
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 uint32_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 }
162}
163
164void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf) {
165 crash_buf.magic = App.get_config_hash();
166 crash_buf.reason = reason;
167 if (esf) {
168 crash_buf.pc = esf->basic.pc;
169 crash_buf.lr = esf->basic.lr;
170 }
171#if defined(CONFIG_THREAD_NAME)
172 auto thread = k_current_get();
173 const char *name = k_thread_name_get(thread);
174 if (name) {
175 strncpy(crash_buf.thread, name, sizeof(crash_buf.thread) - 1);
176 crash_buf.thread[sizeof(crash_buf.thread) - 1] = '\0';
177 } else {
178 crash_buf.thread[0] = '\0';
179 }
180#endif
181 arch_restart();
182}
183
184} // namespace esphome::logger
185
186extern "C" {
187
188void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf) {
190}
191}
192
193#endif
uint32_t get_config_hash()
Get the config hash as a 32-bit integer.
UARTSelection uart_
Definition logger.h:358
void write_msg_(const char *msg, uint16_t len)
const LogString * get_uart_selection_()
void pre_setup()
Set up this component.
const device * uart_dev_
Definition logger.h:320
struct @65::@66 __attribute__
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:278
const char * get_reset_reason(std::span< char, RESET_REASON_BUFFER_SIZE > buffer)
std::string size_t len
Definition helpers.h:817
void HOT arch_feed_wdt()
Definition core.cpp:48
void HOT delay(uint32_t ms)
Definition core.cpp:27
void arch_restart()
Definition core.cpp:30
Application App
Global storage of Application pointer - only one Application can exist.