ESPHome 2025.5.0
Loading...
Searching...
No Matches
uart_component_host.cpp
Go to the documentation of this file.
1#ifdef USE_HOST
6#include "esphome/core/log.h"
7
8#if !(defined(__linux__) || defined(__APPLE__))
9#error This HostUartComponent implementation is not supported on this host OS
10#endif
11
12#include <stdio.h>
13#include <string.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <errno.h>
17#include <termios.h>
18#include <sys/ioctl.h>
19
20#ifdef USE_LOGGER
22#endif
23
24namespace {
25
26speed_t get_baud(int baud) {
27#ifdef __APPLE__
28 return baud;
29#else
30 switch (baud) {
31 case 50:
32 return B50;
33 case 75:
34 return B75;
35 case 110:
36 return B110;
37 case 134:
38 return B134;
39 case 150:
40 return B150;
41 case 200:
42 return B200;
43 case 300:
44 return B300;
45 case 600:
46 return B600;
47 case 1200:
48 return B1200;
49 case 1800:
50 return B1800;
51 case 2400:
52 return B2400;
53 case 4800:
54 return B4800;
55 case 9600:
56 return B9600;
57 case 19200:
58 return B19200;
59 case 38400:
60 return B38400;
61 case 57600:
62 return B57600;
63 case 115200:
64 return B115200;
65 case 230400:
66 return B230400;
67 case 460800:
68 return B460800;
69 case 500000:
70 return B500000;
71 case 576000:
72 return B576000;
73 case 921600:
74 return B921600;
75 case 1000000:
76 return B1000000;
77 case 1152000:
78 return B1152000;
79 case 1500000:
80 return B1500000;
81 case 2000000:
82 return B2000000;
83 case 2500000:
84 return B2500000;
85 case 3000000:
86 return B3000000;
87 case 3500000:
88 return B3500000;
89 case 4000000:
90 return B4000000;
91 default:
92 return B0;
93 }
94#endif
95}
96
97} // namespace
98
99namespace esphome {
100namespace uart {
101
102static const char *const TAG = "uart.host";
103
105 if (this->file_descriptor_ != -1) {
106 close(this->file_descriptor_);
107 this->file_descriptor_ = -1;
108 }
109}
110
112 ESP_LOGCONFIG(TAG, "Opening UART port...");
113 speed_t baud = get_baud(this->baud_rate_);
114 if (baud == B0) {
115 ESP_LOGE(TAG, "Unsupported baud rate: %d", this->baud_rate_);
116 this->mark_failed();
117 return;
118 }
119 this->file_descriptor_ = ::open(this->port_name_.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
120 if (this->file_descriptor_ == -1) {
121 this->update_error_(strerror(errno));
122 this->mark_failed();
123 return;
124 }
125 fcntl(this->file_descriptor_, F_SETFL, 0);
126 struct termios options;
127 tcgetattr(this->file_descriptor_, &options);
128 options.c_cflag &= ~CRTSCTS;
129 options.c_cflag |= CREAD | CLOCAL;
130 options.c_lflag &= ~ICANON;
131 options.c_lflag &= ~ECHO;
132 options.c_lflag &= ~ECHOE;
133 options.c_lflag &= ~ECHONL;
134 options.c_lflag &= ~ISIG;
135 options.c_iflag &= ~(IXON | IXOFF | IXANY);
136 options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
137 options.c_oflag &= ~OPOST;
138 options.c_oflag &= ~ONLCR;
139 // Set data bits
140 options.c_cflag &= ~CSIZE; // Mask the character size bits
141 switch (this->data_bits_) {
142 case 5:
143 options.c_cflag |= CS5;
144 break;
145 case 6:
146 options.c_cflag |= CS6;
147 break;
148 case 7:
149 options.c_cflag |= CS7;
150 break;
151 case 8:
152 default:
153 options.c_cflag |= CS8;
154 break;
155 }
156 // Set parity
157 switch (this->parity_) {
159 options.c_cflag &= ~PARENB;
160 break;
162 options.c_cflag |= PARENB;
163 options.c_cflag &= ~PARODD;
164 break;
166 options.c_cflag |= PARENB;
167 options.c_cflag |= PARODD;
168 break;
169 };
170 // Set stop bits
171 if (this->stop_bits_ == 2) {
172 options.c_cflag |= CSTOPB;
173 } else {
174 options.c_cflag &= ~CSTOPB;
175 }
176 cfsetispeed(&options, baud);
177 cfsetospeed(&options, baud);
178 tcsetattr(this->file_descriptor_, TCSANOW, &options);
179}
180
182 ESP_LOGCONFIG(TAG, "UART:");
183 ESP_LOGCONFIG(TAG, " Port: %s", this->port_name_.c_str());
184 if (this->file_descriptor_ == -1) {
185 ESP_LOGCONFIG(TAG, " Port status: Not opened");
186 if (!this->first_error_.empty()) {
187 ESP_LOGCONFIG(TAG, " Error: %s", this->first_error_.c_str());
188 }
189 return;
190 }
191 ESP_LOGCONFIG(TAG, " Port status: opened");
192 ESP_LOGCONFIG(TAG, " Baud Rate: %d", this->baud_rate_);
193 ESP_LOGCONFIG(TAG, " Data Bits: %d", this->data_bits_);
194 ESP_LOGCONFIG(TAG, " Parity: %s",
195 this->parity_ == UART_CONFIG_PARITY_NONE ? "None"
196 : this->parity_ == UART_CONFIG_PARITY_EVEN ? "Even"
197 : "Odd");
198 ESP_LOGCONFIG(TAG, " Stop Bits: %d", this->stop_bits_);
199 this->check_logger_conflict();
200}
201
202void HostUartComponent::write_array(const uint8_t *data, size_t len) {
203 if (this->file_descriptor_ == -1) {
204 return;
205 }
206 size_t written = ::write(this->file_descriptor_, data, len);
207 if (written != len) {
208 this->update_error_(strerror(errno));
209 return;
210 }
211#ifdef USE_UART_DEBUGGER
212 for (size_t i = 0; i < len; i++) {
213 this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
214 }
215#endif
216 return;
217}
218
219bool HostUartComponent::peek_byte(uint8_t *data) {
220 if (this->file_descriptor_ == -1) {
221 return false;
222 }
223 if (!this->has_peek_) {
224 if (!this->check_read_timeout_()) {
225 return false;
226 }
227 if (::read(this->file_descriptor_, &this->peek_byte_, 1) != 1) {
228 this->update_error_(strerror(errno));
229 return false;
230 }
231 this->has_peek_ = true;
232 }
233 *data = this->peek_byte_;
234 return true;
235}
236
237bool HostUartComponent::read_array(uint8_t *data, size_t len) {
238 if ((this->file_descriptor_ == -1) || (len == 0)) {
239 return false;
240 }
241 if (!this->check_read_timeout_(len))
242 return false;
243 uint8_t *data_ptr = data;
244 size_t length_to_read = len;
245 if (this->has_peek_) {
246 length_to_read--;
247 *data_ptr = this->peek_byte_;
248 data_ptr++;
249 this->has_peek_ = false;
250 }
251 if (length_to_read > 0) {
252 int sz = ::read(this->file_descriptor_, data_ptr, length_to_read);
253 if (sz == -1) {
254 this->update_error_(strerror(errno));
255 return false;
256 }
257 }
258#ifdef USE_UART_DEBUGGER
259 for (size_t i = 0; i < len; i++) {
260 this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
261 }
262#endif
263 return true;
264}
265
267 if (this->file_descriptor_ == -1) {
268 return 0;
269 }
270 int available;
271 int res = ioctl(this->file_descriptor_, FIONREAD, &available);
272 if (res == -1) {
273 this->update_error_(strerror(errno));
274 return 0;
275 }
276 if (this->has_peek_)
277 available++;
278 return available;
279};
280
282 if (this->file_descriptor_ == -1) {
283 return;
284 }
285 tcflush(this->file_descriptor_, TCIOFLUSH);
286 ESP_LOGV(TAG, " Flushing...");
287}
288
289void HostUartComponent::update_error_(const std::string &error) {
290 if (this->first_error_.empty()) {
291 this->first_error_ = error;
292 }
293 ESP_LOGE(TAG, "Port error: %s", error.c_str());
294}
295
296} // namespace uart
297} // namespace esphome
298
299#endif // USE_HOST
virtual void mark_failed()
Mark this component as failed.
bool read_array(uint8_t *data, size_t len) override
void write_array(const uint8_t *data, size_t len) override
void update_error_(const std::string &error)
bool peek_byte(uint8_t *data) override
bool check_read_timeout_(size_t len=1)
CallbackManager< void(UARTDirection, uint8_t)> debug_callback_
uint8_t options
const char *const TAG
Definition spi.cpp:8
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:301