ESPHome 2025.5.0
Loading...
Searching...
No Matches
mcp4461.cpp
Go to the documentation of this file.
1#include "mcp4461.h"
2
4#include "esphome/core/hal.h"
5
6namespace esphome {
7namespace mcp4461 {
8
9static const char *const TAG = "mcp4461";
10constexpr uint8_t EEPROM_WRITE_TIMEOUT_MS = 10;
11
13 ESP_LOGCONFIG(TAG, "Setting up mcp4461 using address (0x%02X)...", this->address_);
14 auto err = this->write(nullptr, 0);
15 if (err != i2c::ERROR_OK) {
16 this->error_code_ = MCP4461_STATUS_I2C_ERROR;
17 this->mark_failed();
18 return;
19 }
20 // save WP/WL status
22 for (uint8_t i = 0; i < 8; i++) {
23 if (this->reg_[i].initial_value.has_value()) {
24 uint16_t initial_state = static_cast<uint16_t>(*this->reg_[i].initial_value * 256.0f);
25 this->write_wiper_level_(i, initial_state);
26 }
27 if (this->reg_[i].enabled) {
28 this->reg_[i].state = this->read_wiper_level_(i);
29 } else {
30 // only volatile wipers can be set disabled on hw level
31 if (i < 4) {
32 this->reg_[i].state = 0;
33 Mcp4461WiperIdx wiper_idx = static_cast<Mcp4461WiperIdx>(i);
34 this->disable_wiper_(wiper_idx);
35 }
36 }
37 }
38}
39
40void Mcp4461Component::set_initial_value(Mcp4461WiperIdx wiper, float initial_value) {
41 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
42 this->reg_[wiper_idx].initial_value = initial_value;
43}
44
46 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
47 switch (terminal) {
48 case 'a':
49 this->reg_[wiper_idx].terminal_a = false;
50 break;
51 case 'b':
52 this->reg_[wiper_idx].terminal_b = false;
53 break;
54 case 'w':
55 this->reg_[wiper_idx].terminal_w = false;
56 break;
57 }
58}
59
61 uint8_t status_register_value = this->get_status_register_();
62 this->write_protected_ = static_cast<bool>((status_register_value >> 0) & 0x01);
63 this->reg_[0].wiper_lock_active = static_cast<bool>((status_register_value >> 2) & 0x01);
64 this->reg_[1].wiper_lock_active = static_cast<bool>((status_register_value >> 3) & 0x01);
65 this->reg_[2].wiper_lock_active = static_cast<bool>((status_register_value >> 5) & 0x01);
66 this->reg_[3].wiper_lock_active = static_cast<bool>((status_register_value >> 6) & 0x01);
67}
68
70 ESP_LOGCONFIG(TAG, "mcp4461:");
71 LOG_I2C_DEVICE(this);
72 if (this->is_failed()) {
73 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
74 }
75 // log wiper status
76 for (uint8_t i = 0; i < 8; ++i) {
77 // terminals only valid for volatile wipers 0-3 - enable/disable is terminal hw
78 // so also invalid for nonvolatile. For these, only print current level.
79 // reworked to be a one-line intentionally, as output would not be in order
80 if (i < 4) {
81 ESP_LOGCONFIG(TAG, " ├── Volatile wiper [%u] level: %u, Status: %s, HW: %s, A: %s, B: %s, W: %s", i,
82 this->reg_[i].state, ONOFF(this->reg_[i].terminal_hw), ONOFF(this->reg_[i].terminal_a),
83 ONOFF(this->reg_[i].terminal_b), ONOFF(this->reg_[i].terminal_w), ONOFF(this->reg_[i].enabled));
84 } else {
85 ESP_LOGCONFIG(TAG, " ├── Nonvolatile wiper [%u] level: %u", i, this->reg_[i].state);
86 }
87 }
88}
89
91 if (this->status_has_warning()) {
93 }
94 for (uint8_t i = 0; i < 8; i++) {
95 if (this->reg_[i].update_level) {
96 // set wiper i state if changed
97 if (this->reg_[i].state != this->read_wiper_level_(i)) {
98 this->write_wiper_level_(i, this->reg_[i].state);
99 }
100 }
101 this->reg_[i].update_level = false;
102 // can be true only for wipers 0-3
103 // setting changes for terminals of nonvolatile wipers
104 // is prohibited in public methods
105 if (this->reg_[i].update_terminal) {
106 // set terminal register changes
107 Mcp4461TerminalIdx terminal_connector =
109 uint8_t new_terminal_value = this->calc_terminal_connector_byte_(terminal_connector);
110 ESP_LOGV(TAG, "updating terminal %u to new value %u", static_cast<uint8_t>(terminal_connector),
111 new_terminal_value);
112 this->set_terminal_register_(terminal_connector, new_terminal_value);
113 }
114 this->reg_[i].update_terminal = false;
115 }
116}
117
119 if (this->is_failed()) {
120 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
121 return 0;
122 }
123 uint8_t addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_STATUS);
124 uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::READ);
125 uint16_t buf;
126 if (!this->read_byte_16(reg, &buf)) {
127 this->error_code_ = MCP4461_STATUS_REGISTER_ERROR;
128 this->mark_failed();
129 return 0;
130 }
131 uint8_t msb = buf >> 8;
132 uint8_t lsb = static_cast<uint8_t>(buf & 0x00ff);
133 if (msb != 1 || ((lsb >> 7) & 0x01) != 1 || ((lsb >> 1) & 0x01) != 1) {
134 // D8, D7 and R1 bits are hardlocked to 1 -> a status msb bit 0 (bit 9 of status register) of 0 or lsb bit 1/7 = 0
135 // indicate device/communication issues, therefore mark component failed
136 this->error_code_ = MCP4461_STATUS_REGISTER_INVALID;
137 this->mark_failed();
138 return 0;
139 }
140 this->status_clear_warning();
141 return lsb;
142}
143
145 uint8_t status_register_value = this->get_status_register_();
146 ESP_LOGI(TAG, "D7: %u, WL3: %u, WL2: %u, EEWA: %u, WL1: %u, WL0: %u, R1: %u, WP: %u",
147 ((status_register_value >> 7) & 0x01), ((status_register_value >> 6) & 0x01),
148 ((status_register_value >> 5) & 0x01), ((status_register_value >> 4) & 0x01),
149 ((status_register_value >> 3) & 0x01), ((status_register_value >> 2) & 0x01),
150 ((status_register_value >> 1) & 0x01), ((status_register_value >> 0) & 0x01));
151}
152
154 uint8_t addr;
155 bool nonvolatile = false;
156 if (wiper > 3) {
157 nonvolatile = true;
158 wiper = wiper - 4;
159 }
160 switch (wiper) {
161 case 0:
162 addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_VW0);
163 break;
164 case 1:
165 addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_VW1);
166 break;
167 case 2:
168 addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_VW2);
169 break;
170 case 3:
171 addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_VW3);
172 break;
173 default:
174 ESP_LOGW(TAG, "unknown wiper specified");
175 return 0;
176 }
177 if (nonvolatile) {
178 addr = addr + 0x20;
179 }
180 return addr;
181}
182
184 if (this->is_failed()) {
185 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
186 return 0;
187 }
188 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
189 if (!(this->reg_[wiper_idx].enabled)) {
190 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
191 return 0;
192 }
193 if (!(this->reg_[wiper_idx].enabled)) {
194 ESP_LOGW(TAG, "reading from disabled volatile wiper %u, returning 0", wiper_idx);
195 return 0;
196 }
197 return this->read_wiper_level_(wiper_idx);
198}
199
200uint16_t Mcp4461Component::read_wiper_level_(uint8_t wiper_idx) {
201 uint8_t addr = this->get_wiper_address_(wiper_idx);
202 uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::INCREMENT);
203 if (wiper_idx > 3) {
204 if (!this->is_eeprom_ready_for_writing_(true)) {
205 return 0;
206 }
207 }
208 uint16_t buf = 0;
209 if (!(this->read_byte_16(reg, &buf))) {
210 this->error_code_ = MCP4461_STATUS_I2C_ERROR;
211 this->status_set_warning();
212 ESP_LOGW(TAG, "Error fetching %swiper %u value", (wiper_idx > 3) ? "nonvolatile " : "", wiper_idx);
213 return 0;
214 }
215 return buf;
216}
217
219 if (this->is_failed()) {
220 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
221 return false;
222 }
223 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
224 if (!(this->reg_[wiper_idx].enabled)) {
225 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
226 return false;
227 }
228 uint16_t data = this->get_wiper_level_(wiper);
229 ESP_LOGV(TAG, "Got value %u from wiper %u", data, wiper_idx);
230 this->reg_[wiper_idx].state = data;
231 return true;
232}
233
235 if (this->is_failed()) {
236 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
237 return false;
238 }
239 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
240 if (value > 0x100) {
241 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_VALUE_INVALID)));
242 return false;
243 }
244 if (!(this->reg_[wiper_idx].enabled)) {
245 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
246 return false;
247 }
248 if (this->reg_[wiper_idx].wiper_lock_active) {
249 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_LOCKED)));
250 return false;
251 }
252 ESP_LOGV(TAG, "Setting MCP4461 wiper %u to %u", wiper_idx, value);
253 this->reg_[wiper_idx].state = value;
254 this->reg_[wiper_idx].update_level = true;
255 return true;
256}
257
258void Mcp4461Component::write_wiper_level_(uint8_t wiper, uint16_t value) {
259 bool nonvolatile = wiper > 3;
260 if (!(this->mcp4461_write_(this->get_wiper_address_(wiper), value, nonvolatile))) {
261 this->error_code_ = MCP4461_STATUS_I2C_ERROR;
262 this->status_set_warning();
263 ESP_LOGW(TAG, "Error writing %swiper %u level %u", (wiper > 3) ? "nonvolatile " : "", wiper, value);
264 }
265}
266
268 if (this->is_failed()) {
269 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
270 return;
271 }
272 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
273 if ((this->reg_[wiper_idx].enabled)) {
274 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_ENABLED)));
275 return;
276 }
277 if (this->reg_[wiper_idx].wiper_lock_active) {
278 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_LOCKED)));
279 return;
280 }
281 ESP_LOGV(TAG, "Enabling wiper %u", wiper_idx);
282 this->reg_[wiper_idx].enabled = true;
283 if (wiper_idx < 4) {
284 this->reg_[wiper_idx].terminal_hw = true;
285 this->reg_[wiper_idx].update_terminal = true;
286 }
287}
288
290 if (this->is_failed()) {
291 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
292 return;
293 }
294 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
295 if (!(this->reg_[wiper_idx].enabled)) {
296 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
297 return;
298 }
299 if (this->reg_[wiper_idx].wiper_lock_active) {
300 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_LOCKED)));
301 return;
302 }
303 ESP_LOGV(TAG, "Disabling wiper %u", wiper_idx);
304 this->reg_[wiper_idx].enabled = true;
305 if (wiper_idx < 4) {
306 this->reg_[wiper_idx].terminal_hw = true;
307 this->reg_[wiper_idx].update_terminal = true;
308 }
309}
310
312 if (this->is_failed()) {
313 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
314 return false;
315 }
316 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
317 if (!(this->reg_[wiper_idx].enabled)) {
318 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
319 return false;
320 }
321 if (this->reg_[wiper_idx].wiper_lock_active) {
322 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_LOCKED)));
323 return false;
324 }
325 if (this->reg_[wiper_idx].state == 256) {
326 ESP_LOGV(TAG, "Maximum wiper level reached, further increase of wiper %u prohibited", wiper_idx);
327 return false;
328 }
329 ESP_LOGV(TAG, "Increasing wiper %u", wiper_idx);
330 uint8_t addr = this->get_wiper_address_(wiper_idx);
331 uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::INCREMENT);
332 auto err = this->write(&this->address_, reg, sizeof(reg));
333 if (err != i2c::ERROR_OK) {
334 this->error_code_ = MCP4461_STATUS_I2C_ERROR;
335 this->status_set_warning();
336 return false;
337 }
338 this->reg_[wiper_idx].state++;
339 return true;
340}
341
343 if (this->is_failed()) {
344 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
345 return false;
346 }
347 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
348 if (!(this->reg_[wiper_idx].enabled)) {
349 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
350 return false;
351 }
352 if (this->reg_[wiper_idx].wiper_lock_active) {
353 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_LOCKED)));
354 return false;
355 }
356 if (this->reg_[wiper_idx].state == 0) {
357 ESP_LOGV(TAG, "Minimum wiper level reached, further decrease of wiper %u prohibited", wiper_idx);
358 return false;
359 }
360 ESP_LOGV(TAG, "Decreasing wiper %u", wiper_idx);
361 uint8_t addr = this->get_wiper_address_(wiper_idx);
362 uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::DECREMENT);
363 auto err = this->write(&this->address_, reg, sizeof(reg));
364 if (err != i2c::ERROR_OK) {
365 this->error_code_ = MCP4461_STATUS_I2C_ERROR;
366 this->status_set_warning();
367 return false;
368 }
369 this->reg_[wiper_idx].state--;
370 return true;
371}
372
374 uint8_t i = static_cast<uint8_t>(terminal_connector) <= 1 ? 0 : 2;
375 uint8_t new_value_byte = 0;
376 new_value_byte += static_cast<uint8_t>(this->reg_[i].terminal_b);
377 new_value_byte += static_cast<uint8_t>(this->reg_[i].terminal_w) << 1;
378 new_value_byte += static_cast<uint8_t>(this->reg_[i].terminal_a) << 2;
379 new_value_byte += static_cast<uint8_t>(this->reg_[i].terminal_hw) << 3;
380 new_value_byte += static_cast<uint8_t>(this->reg_[(i + 1)].terminal_b) << 4;
381 new_value_byte += static_cast<uint8_t>(this->reg_[(i + 1)].terminal_w) << 5;
382 new_value_byte += static_cast<uint8_t>(this->reg_[(i + 1)].terminal_a) << 6;
383 new_value_byte += static_cast<uint8_t>(this->reg_[(i + 1)].terminal_hw) << 7;
384 return new_value_byte;
385}
386
388 if (this->is_failed()) {
389 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
390 return 0;
391 }
392 uint8_t reg = static_cast<uint8_t>(terminal_connector) == 0 ? static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON0)
393 : static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON1);
394 reg |= static_cast<uint8_t>(Mcp4461Commands::READ);
395 uint16_t buf;
396 if (this->read_byte_16(reg, &buf)) {
397 return static_cast<uint8_t>(buf & 0x00ff);
398 } else {
399 this->error_code_ = MCP4461_STATUS_I2C_ERROR;
400 this->status_set_warning();
401 ESP_LOGW(TAG, "Error fetching terminal register value");
402 return 0;
403 }
404}
405
407 if (this->is_failed()) {
408 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
409 return;
410 }
411 if ((static_cast<uint8_t>(terminal_connector) != 0 && static_cast<uint8_t>(terminal_connector) != 1)) {
412 return;
413 }
414 uint8_t terminal_data = this->get_terminal_register_(terminal_connector);
415 if (terminal_data == 0) {
416 return;
417 }
418 ESP_LOGV(TAG, "Got terminal register %u data 0x%02X", static_cast<uint8_t>(terminal_connector), terminal_data);
419 uint8_t wiper_index = 0;
420 if (static_cast<uint8_t>(terminal_connector) == 1) {
421 wiper_index = 2;
422 }
423 this->reg_[wiper_index].terminal_b = ((terminal_data >> 0) & 0x01);
424 this->reg_[wiper_index].terminal_w = ((terminal_data >> 1) & 0x01);
425 this->reg_[wiper_index].terminal_a = ((terminal_data >> 2) & 0x01);
426 this->reg_[wiper_index].terminal_hw = ((terminal_data >> 3) & 0x01);
427 this->reg_[(wiper_index + 1)].terminal_b = ((terminal_data >> 4) & 0x01);
428 this->reg_[(wiper_index + 1)].terminal_w = ((terminal_data >> 5) & 0x01);
429 this->reg_[(wiper_index + 1)].terminal_a = ((terminal_data >> 6) & 0x01);
430 this->reg_[(wiper_index + 1)].terminal_hw = ((terminal_data >> 7) & 0x01);
431}
432
433bool Mcp4461Component::set_terminal_register_(Mcp4461TerminalIdx terminal_connector, uint8_t data) {
434 if (this->is_failed()) {
435 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
436 return false;
437 }
438 uint8_t addr;
439 if (static_cast<uint8_t>(terminal_connector) == 0) {
440 addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON0);
441 } else if (static_cast<uint8_t>(terminal_connector) == 1) {
442 addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON1);
443 } else {
444 ESP_LOGW(TAG, "Invalid terminal connector id %u specified", static_cast<uint8_t>(terminal_connector));
445 return false;
446 }
447 if (!(this->mcp4461_write_(addr, data))) {
448 this->error_code_ = MCP4461_STATUS_I2C_ERROR;
449 this->status_set_warning();
450 return false;
451 }
452 return true;
453}
454
456 if (this->is_failed()) {
457 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
458 return;
459 }
460 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
461 ESP_LOGV(TAG, "Enabling terminal %c of wiper %u", terminal, wiper_idx);
462 switch (terminal) {
463 case 'h':
464 this->reg_[wiper_idx].terminal_hw = true;
465 break;
466 case 'a':
467 this->reg_[wiper_idx].terminal_a = true;
468 break;
469 case 'b':
470 this->reg_[wiper_idx].terminal_b = true;
471 break;
472 case 'w':
473 this->reg_[wiper_idx].terminal_w = true;
474 break;
475 default:
476 ESP_LOGW(TAG, "Unknown terminal %c specified", terminal);
477 return;
478 }
479 this->reg_[wiper_idx].update_terminal = false;
480}
481
483 if (this->is_failed()) {
484 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
485 return;
486 }
487 uint8_t wiper_idx = static_cast<uint8_t>(wiper);
488 ESP_LOGV(TAG, "Disabling terminal %c of wiper %u", terminal, wiper_idx);
489 switch (terminal) {
490 case 'h':
491 this->reg_[wiper_idx].terminal_hw = false;
492 break;
493 case 'a':
494 this->reg_[wiper_idx].terminal_a = false;
495 break;
496 case 'b':
497 this->reg_[wiper_idx].terminal_b = false;
498 break;
499 case 'w':
500 this->reg_[wiper_idx].terminal_w = false;
501 break;
502 default:
503 ESP_LOGW(TAG, "Unknown terminal %c specified", terminal);
504 return;
505 }
506 this->reg_[wiper_idx].update_terminal = false;
507}
508
510 if (this->is_failed()) {
511 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
512 return 0;
513 }
514 uint8_t reg = 0;
515 reg |= static_cast<uint8_t>(Mcp4461EepromLocation::MCP4461_EEPROM_1) + (static_cast<uint8_t>(location) * 0x10);
516 reg |= static_cast<uint8_t>(Mcp4461Commands::READ);
517 uint16_t buf;
518 if (!this->is_eeprom_ready_for_writing_(true)) {
519 return 0;
520 }
521 if (!this->read_byte_16(reg, &buf)) {
522 this->error_code_ = MCP4461_STATUS_I2C_ERROR;
523 this->status_set_warning();
524 ESP_LOGW(TAG, "Error fetching EEPROM location value");
525 return 0;
526 }
527 return buf;
528}
529
531 if (this->is_failed()) {
532 ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
533 return false;
534 }
535 uint8_t addr = 0;
536 if (value > 511) {
537 return false;
538 }
539 if (value > 256) {
540 addr = 1;
541 }
542 addr |= static_cast<uint8_t>(Mcp4461EepromLocation::MCP4461_EEPROM_1) + (static_cast<uint8_t>(location) * 0x10);
543 if (!(this->mcp4461_write_(addr, value, true))) {
544 this->error_code_ = MCP4461_STATUS_I2C_ERROR;
545 this->status_set_warning();
546 ESP_LOGW(TAG, "Error writing EEPROM value");
547 return false;
548 }
549 return true;
550}
551
553 /* Read the EEPROM write-active status from the status register */
554 bool writing = static_cast<bool>((this->get_status_register_() >> 4) & 0x01);
555
556 /* If EEPROM is no longer writing, reset the timeout flag */
557 if (!writing) {
558 /* This is protected boolean flag in Mcp4461Component class */
559 this->last_eeprom_write_timed_out_ = false;
560 }
561
562 return writing;
563}
564
566 /* Check initial write status */
567 bool ready_for_write = !this->is_writing_();
568
569 /* Return early if no waiting is required or EEPROM is already ready */
570 if (ready_for_write || !wait_if_not_ready || this->last_eeprom_write_timed_out_) {
571 return ready_for_write;
572 }
573
574 /* Timestamp before starting the loop */
575 const uint32_t start_millis = millis();
576
577 ESP_LOGV(TAG, "Waiting until EEPROM is ready for write, start_millis = %" PRIu32, start_millis);
578
579 /* Loop until EEPROM is ready or timeout is reached */
580 while (!ready_for_write && ((millis() - start_millis) < EEPROM_WRITE_TIMEOUT_MS)) {
581 ready_for_write = !this->is_writing_();
582
583 /* If ready, exit early */
584 if (ready_for_write) {
585 ESP_LOGV(TAG, "EEPROM is ready for new write, elapsed_millis = %" PRIu32, millis() - start_millis);
586 return true;
587 }
588
589 /* Not ready yet, yield before checking again */
590 yield();
591 }
592
593 /* If still not ready after timeout, log error and mark the timeout */
594 ESP_LOGE(TAG, "EEPROM write timeout exceeded (%u ms)", EEPROM_WRITE_TIMEOUT_MS);
595 this->last_eeprom_write_timed_out_ = true;
596
597 return false;
598}
599
600bool Mcp4461Component::mcp4461_write_(uint8_t addr, uint16_t data, bool nonvolatile) {
601 uint8_t reg = data > 0xff ? 1 : 0;
602 uint8_t value_byte = static_cast<uint8_t>(data & 0x00ff);
603 ESP_LOGV(TAG, "Writing value %u to address %u", data, addr);
604 reg |= addr;
605 reg |= static_cast<uint8_t>(Mcp4461Commands::WRITE);
606 if (nonvolatile) {
607 if (this->write_protected_) {
608 ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WRITE_PROTECTED)));
609 return false;
610 }
611 if (!this->is_eeprom_ready_for_writing_(true)) {
612 return false;
613 }
614 }
615 return this->write_byte(reg, value_byte);
616}
617} // namespace mcp4461
618} // namespace esphome
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
bool status_has_warning() const
void status_set_warning(const char *message="unspecified")
void status_clear_warning()
ErrorCode write(const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a device using an I2CBus
Definition i2c.h:190
uint8_t address_
store the address of the device on the bus
Definition i2c.h:273
bool write_byte(uint8_t a_register, uint8_t data, bool stop=true)
Definition i2c.h:266
bool read_byte_16(uint8_t a_register, uint16_t *data)
Definition i2c.h:250
I2CRegister reg(uint8_t a_register)
calls the I2CRegister constructor
Definition i2c.h:153
void set_initial_value(Mcp4461WiperIdx wiper, float initial_value)
public function used to set initial value
Definition mcp4461.cpp:40
bool increase_wiper_(Mcp4461WiperIdx wiper)
Definition mcp4461.cpp:311
uint8_t calc_terminal_connector_byte_(Mcp4461TerminalIdx terminal_connector)
Definition mcp4461.cpp:373
uint8_t get_terminal_register_(Mcp4461TerminalIdx terminal_connector)
Definition mcp4461.cpp:387
void update_terminal_register_(Mcp4461TerminalIdx terminal_connector)
Definition mcp4461.cpp:406
uint16_t get_eeprom_value(Mcp4461EepromLocation location)
get eeprom value from location
Definition mcp4461.cpp:509
bool set_eeprom_value(Mcp4461EepromLocation location, uint16_t value)
set eeprom value at specified location
Definition mcp4461.cpp:530
void disable_wiper_(Mcp4461WiperIdx wiper)
Definition mcp4461.cpp:289
void initialize_terminal_disabled(Mcp4461WiperIdx wiper, char terminal)
public function used to set disable terminal config
Definition mcp4461.cpp:45
void enable_wiper_(Mcp4461WiperIdx wiper)
Definition mcp4461.cpp:267
uint16_t read_wiper_level_(uint8_t wiper)
Definition mcp4461.cpp:200
bool mcp4461_write_(uint8_t addr, uint16_t data, bool nonvolatile=false)
Definition mcp4461.cpp:600
void enable_terminal_(Mcp4461WiperIdx wiper, char terminal)
Definition mcp4461.cpp:455
bool is_eeprom_ready_for_writing_(bool wait_if_not_ready)
Definition mcp4461.cpp:565
uint16_t get_wiper_level_(Mcp4461WiperIdx wiper)
Definition mcp4461.cpp:183
static const LogString * get_message_string(int status)
Definition mcp4461.h:122
bool update_wiper_level_(Mcp4461WiperIdx wiper)
Definition mcp4461.cpp:218
uint8_t get_wiper_address_(uint8_t wiper)
Definition mcp4461.cpp:153
void disable_terminal_(Mcp4461WiperIdx, char terminal)
Definition mcp4461.cpp:482
void write_wiper_level_(uint8_t wiper, uint16_t value)
Definition mcp4461.cpp:258
bool decrease_wiper_(Mcp4461WiperIdx wiper)
Definition mcp4461.cpp:342
bool set_terminal_register_(Mcp4461TerminalIdx terminal_connector, uint8_t data)
Definition mcp4461.cpp:433
bool set_wiper_level_(Mcp4461WiperIdx wiper, uint16_t value)
Definition mcp4461.cpp:234
void read_status_register_to_log()
read status register to log
Definition mcp4461.cpp:144
bool state
Definition fan.h:0
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:13
constexpr uint8_t EEPROM_WRITE_TIMEOUT_MS
Definition mcp4461.cpp:10
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void IRAM_ATTR HOT yield()
Definition core.cpp:26
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:27
optional< float > initial_value
Definition mcp4461.h:13