ESPHome 2026.1.0-dev
Loading...
Searching...
No Matches
uart_debugger.cpp
Go to the documentation of this file.
2#ifdef USE_UART_DEBUGGER
3
4#include <vector>
5#include "uart_debugger.h"
7#include "esphome/core/log.h"
8
9namespace esphome::uart {
10
11static const char *const TAG = "uart_debug";
12
14 parent->add_debug_callback([this](UARTDirection direction, uint8_t byte) {
15 if (!this->is_my_direction_(direction) || this->is_recursive_()) {
16 return;
17 }
18 this->trigger_after_direction_change_(direction);
19 this->store_byte_(direction, byte);
20 this->trigger_after_delimiter_(byte);
22 });
23}
24
26
30
32
39
41 this->bytes_.push_back(byte);
43 this->last_time_ = millis();
44}
45
47 if (this->after_delimiter_.empty() || !this->has_buffered_bytes_()) {
48 return;
49 }
50 if (this->after_delimiter_[this->after_delimiter_pos_] != byte) {
51 this->after_delimiter_pos_ = 0;
52 return;
53 }
55 if (this->after_delimiter_pos_ == this->after_delimiter_.size()) {
56 this->fire_trigger_();
57 this->after_delimiter_pos_ = 0;
58 }
59}
60
62 if (this->has_buffered_bytes_() && this->after_bytes_ > 0 && this->bytes_.size() >= this->after_bytes_) {
63 this->fire_trigger_();
64 }
65}
66
68 if (this->has_buffered_bytes_() && this->after_timeout_ > 0 && millis() - this->last_time_ >= this->after_timeout_) {
69 this->fire_trigger_();
70 }
71}
72
73bool UARTDebugger::has_buffered_bytes_() { return !this->bytes_.empty(); }
74
76 this->is_triggering_ = true;
77 trigger(this->last_direction_, this->bytes_);
78 this->bytes_.clear();
79 this->is_triggering_ = false;
80}
81
83 // Reading up to a limited number of bytes, to make sure that this loop()
84 // won't lock up the system on a continuous incoming stream of bytes.
85 uint8_t data;
86 int count = 50;
87 while (this->available() && count--) {
88 this->read_byte(&data);
89 }
90}
91
92// In the upcoming log functions, a delay was added after all log calls.
93// This is done to allow the system to ship the log lines via the API
94// TCP connection(s). Without these delays, debug log lines could go
95// missing when UART devices block the main loop for too long.
96
97void UARTDebug::log_hex(UARTDirection direction, std::vector<uint8_t> bytes, uint8_t separator) {
98 std::string res;
100 res += "<<< ";
101 } else {
102 res += ">>> ";
103 }
104 size_t len = bytes.size();
105 char buf[5];
106 for (size_t i = 0; i < len; i++) {
107 if (i > 0) {
108 res += separator;
109 }
110 sprintf(buf, "%02X", bytes[i]);
111 res += buf;
112 }
113 ESP_LOGD(TAG, "%s", res.c_str());
114 delay(10);
115}
116
117void UARTDebug::log_string(UARTDirection direction, std::vector<uint8_t> bytes) {
118 std::string res;
120 res += "<<< \"";
121 } else {
122 res += ">>> \"";
123 }
124 size_t len = bytes.size();
125 char buf[5];
126 for (size_t i = 0; i < len; i++) {
127 if (bytes[i] == 7) {
128 res += "\\a";
129 } else if (bytes[i] == 8) {
130 res += "\\b";
131 } else if (bytes[i] == 9) {
132 res += "\\t";
133 } else if (bytes[i] == 10) {
134 res += "\\n";
135 } else if (bytes[i] == 11) {
136 res += "\\v";
137 } else if (bytes[i] == 12) {
138 res += "\\f";
139 } else if (bytes[i] == 13) {
140 res += "\\r";
141 } else if (bytes[i] == 27) {
142 res += "\\e";
143 } else if (bytes[i] == 34) {
144 res += "\\\"";
145 } else if (bytes[i] == 39) {
146 res += "\\'";
147 } else if (bytes[i] == 92) {
148 res += "\\\\";
149 } else if (bytes[i] < 32 || bytes[i] > 127) {
150 sprintf(buf, "\\x%02X", bytes[i]);
151 res += buf;
152 } else {
153 res += bytes[i];
154 }
155 }
156 res += '"';
157 ESP_LOGD(TAG, "%s", res.c_str());
158 delay(10);
159}
160
161void UARTDebug::log_int(UARTDirection direction, std::vector<uint8_t> bytes, uint8_t separator) {
162 std::string res;
163 size_t len = bytes.size();
165 res += "<<< ";
166 } else {
167 res += ">>> ";
168 }
169 for (size_t i = 0; i < len; i++) {
170 if (i > 0) {
171 res += separator;
172 }
173 res += to_string(bytes[i]);
174 }
175 ESP_LOGD(TAG, "%s", res.c_str());
176 delay(10);
177}
178
179void UARTDebug::log_binary(UARTDirection direction, std::vector<uint8_t> bytes, uint8_t separator) {
180 std::string res;
181 size_t len = bytes.size();
183 res += "<<< ";
184 } else {
185 res += ">>> ";
186 }
187 char buf[20];
188 for (size_t i = 0; i < len; i++) {
189 if (i > 0) {
190 res += separator;
191 }
192 sprintf(buf, "0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", BYTE_TO_BINARY(bytes[i]), bytes[i]);
193 res += buf;
194 }
195 ESP_LOGD(TAG, "%s", res.c_str());
196 delay(10);
197}
198
199} // namespace esphome::uart
200#endif
void add_debug_callback(std::function< void(UARTDirection, uint8_t)> &&callback)
static void log_hex(UARTDirection direction, std::vector< uint8_t > bytes, uint8_t separator)
Log the bytes as hex values, separated by the provided separator character.
static void log_binary(UARTDirection direction, std::vector< uint8_t > bytes, uint8_t separator)
Log the bytes as '<binary> (<hex>)' values, separated by the provided separator.
static void log_string(UARTDirection direction, std::vector< uint8_t > bytes)
Log the bytes as string values, escaping unprintable characters.
static void log_int(UARTDirection direction, std::vector< uint8_t > bytes, uint8_t separator)
Log the bytes as integer values, separated by the provided separator character.
void store_byte_(UARTDirection direction, uint8_t byte)
bool is_my_direction_(UARTDirection direction)
void trigger_after_direction_change_(UARTDirection direction)
std::vector< uint8_t > bytes_
std::vector< uint8_t > after_delimiter_
void trigger_after_delimiter_(uint8_t byte)
UARTDebugger(UARTComponent *parent)
bool read_byte(uint8_t *data)
Definition uart.h:34
FanDirection direction
Definition fan.h:3
const char *const TAG
Definition spi.cpp:7
std::string size_t len
Definition helpers.h:533
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:26
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:25