ESPHome 2026.4.0-dev
Loading...
Searching...
No Matches
task_log_buffer_libretiny.cpp
Go to the documentation of this file.
1#ifdef USE_LIBRETINY
2
4#include "esphome/core/log.h"
5
6#ifdef USE_ESPHOME_TASK_LOG_BUFFER
7
8namespace esphome::logger {
9
11 // Create mutex for thread-safe access
12 // Storage is a member array (embedded in Logger), no heap allocation needed
13 this->mutex_ = xSemaphoreCreateMutex();
14}
15
17 if (this->mutex_ != nullptr) {
18 vSemaphoreDelete(this->mutex_);
19 this->mutex_ = nullptr;
20 }
21}
22
23size_t TaskLogBuffer::available_contiguous_space() const {
24 if (this->head_ >= this->tail_) {
25 // head is ahead of or equal to tail
26 // Available space is from head to end, plus from start to tail
27 // But for contiguous, just from head to end (minus 1 to avoid head==tail ambiguity)
28 size_t space_to_end = ESPHOME_TASK_LOG_BUFFER_SIZE - this->head_;
29 if (this->tail_ == 0) {
30 // Can't use the last byte or head would equal tail
31 return space_to_end > 0 ? space_to_end - 1 : 0;
32 }
33 return space_to_end;
34 } else {
35 // tail is ahead of head
36 // Available contiguous space is from head to tail - 1
37 return this->tail_ - this->head_ - 1;
38 }
39}
40
41bool TaskLogBuffer::borrow_message_main_loop(LogMessage *&message, uint16_t &text_length) {
42 // Check if mutex was initialized successfully
43 if (this->mutex_ == nullptr) {
44 return false;
45 }
46
47 // Try to take mutex without blocking - if busy, we'll get messages next loop iteration
48 if (xSemaphoreTake(this->mutex_, 0) != pdTRUE) {
49 return false;
50 }
51
52 if (this->head_ == this->tail_) {
53 xSemaphoreGive(this->mutex_);
54 return false;
55 }
56
57 // Read message header from tail
58 LogMessage *msg = reinterpret_cast<LogMessage *>(this->storage_ + this->tail_);
59
60 // Check for padding marker (indicates wrap-around)
61 // We check the level field since valid levels are 0-7, and 0xFF indicates padding
62 if (msg->level == PADDING_MARKER_LEVEL) {
63 // Skip to start of buffer and re-read
64 this->tail_ = 0;
65 msg = reinterpret_cast<LogMessage *>(this->storage_);
66 }
67 message = msg;
68 text_length = msg->text_length;
69 this->current_message_size_ = message_total_size(msg->text_length);
70
71 // Keep mutex held until release_message_main_loop()
72 return true;
73}
74
76 // Advance tail past the current message
77 this->tail_ += this->current_message_size_;
78
79 // Handle wrap-around if we've reached the end
80 if (this->tail_ >= ESPHOME_TASK_LOG_BUFFER_SIZE) {
81 this->tail_ = 0;
82 }
83
84 this->message_count_--;
85 this->current_message_size_ = 0;
86
87 xSemaphoreGive(this->mutex_);
88}
89
90bool TaskLogBuffer::send_message_thread_safe(uint8_t level, const char *tag, uint16_t line, const char *thread_name,
91 const char *format, va_list args) {
92 // First, calculate the exact length needed using a null buffer (no actual writing)
93 va_list args_copy;
94 va_copy(args_copy, args);
95 int ret = vsnprintf(nullptr, 0, format, args_copy);
96 va_end(args_copy);
97
98 if (ret <= 0) {
99 return false; // Formatting error or empty message
100 }
101
102 // Calculate actual text length (capped to maximum size)
103 static constexpr size_t MAX_TEXT_SIZE = 255;
104 size_t text_length = (static_cast<size_t>(ret) > MAX_TEXT_SIZE) ? MAX_TEXT_SIZE : ret;
105
106 // Calculate total size needed (header + text length + null terminator)
107 size_t total_size = message_total_size(text_length);
108
109 // Check if mutex was initialized successfully
110 if (this->mutex_ == nullptr) {
111 return false; // Mutex not initialized, fall back to direct output
112 }
113
114 // Try to acquire mutex without blocking - don't block logging tasks
115 if (xSemaphoreTake(this->mutex_, 0) != pdTRUE) {
116 return false; // Mutex busy, fall back to direct output
117 }
118
119 // Check if we have enough contiguous space
120 size_t contiguous = this->available_contiguous_space();
121
122 if (contiguous < total_size) {
123 // Not enough contiguous space at end
124 // Check if we can wrap around
125 size_t space_at_start = (this->head_ >= this->tail_) ? this->tail_ : 0;
126 if (space_at_start > 0) {
127 space_at_start--; // Leave 1 byte gap to distinguish full from empty
128 }
129
130 // Need at least enough space to safely write padding marker (level field is at end of struct)
131 constexpr size_t PADDING_MARKER_MIN_SPACE = offsetof(LogMessage, level) + 1;
132
133 if (space_at_start >= total_size && this->head_ > 0 && contiguous >= PADDING_MARKER_MIN_SPACE) {
134 // Add padding marker (set level field to indicate this is padding, not a real message)
135 LogMessage *padding = reinterpret_cast<LogMessage *>(this->storage_ + this->head_);
136 padding->level = PADDING_MARKER_LEVEL;
137 this->head_ = 0;
138 } else {
139 // Not enough space anywhere, or can't safely write padding marker
140 xSemaphoreGive(this->mutex_);
141 return false;
142 }
143 }
144
145 // Write message header
146 LogMessage *msg = reinterpret_cast<LogMessage *>(this->storage_ + this->head_);
147 msg->level = level;
148 msg->tag = tag;
149 msg->line = line;
150
151 // Store the thread name now to avoid crashes if task is deleted before processing
152 if (thread_name != nullptr) {
153 strncpy(msg->thread_name, thread_name, sizeof(msg->thread_name) - 1);
154 msg->thread_name[sizeof(msg->thread_name) - 1] = '\0';
155 } else {
156 msg->thread_name[0] = '\0';
157 }
158
159 // Format the message text directly into the buffer
160 char *text_area = msg->text_data();
161 ret = vsnprintf(text_area, text_length + 1, format, args);
162
163 if (ret <= 0) {
164 xSemaphoreGive(this->mutex_);
165 return false;
166 }
167
168 // Remove trailing newlines
169 while (text_length > 0 && text_area[text_length - 1] == '\n') {
170 text_length--;
171 }
172
173 msg->text_length = text_length;
174
175 // Advance head
176 this->head_ += total_size;
177
178 // Handle wrap-around (shouldn't happen due to contiguous space check, but be safe)
179 if (this->head_ >= ESPHOME_TASK_LOG_BUFFER_SIZE) {
180 this->head_ = 0;
181 }
182
183 this->message_count_++;
184
185 xSemaphoreGive(this->mutex_);
186 return true;
187}
188
189} // namespace esphome::logger
190
191#endif // USE_ESPHOME_TASK_LOG_BUFFER
192#endif // USE_LIBRETINY
bool borrow_message_main_loop(LogMessage *&message, uint16_t &text_length)
bool send_message_thread_safe(uint8_t level, const char *tag, uint16_t line, const char *thread_name, const char *format, va_list args)
static constexpr uint8_t PADDING_MARKER_LEVEL
const char * message
Definition component.cpp:35
const char int line
Definition log.h:74
const char * tag
Definition log.h:74
const char int const __FlashStringHelper * format
Definition log.h:74
const char int const __FlashStringHelper va_list args
Definition log.h:74
va_end(args)