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