Arduino.h 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #pragma once
  2. // Minimal Arduino.h substitute for compiling GxEPD2 under ESP-IDF. GxEPD2's
  3. // vendored source calls down into a small, fixed set of Arduino primitives
  4. // (digitalWrite/pinMode/digitalRead on plain int16_t pin numbers, plus
  5. // delay/micros/yield) - this shim backs them with esphome::GPIOPin via
  6. // PinRegistry, so GxEPD2 compiles completely unmodified against it.
  7. #include <cstdint>
  8. #include <sstream>
  9. #include <string>
  10. #include <esp_task_wdt.h>
  11. #include "esphome/core/hal.h"
  12. #include "esphome/core/log.h"
  13. #include "esphome/components/gxepd2/pin_registry.h"
  14. #ifndef ESP32
  15. #define ESP32
  16. #endif
  17. #define HIGH 1
  18. #define LOW 0
  19. #define INPUT 0
  20. #define OUTPUT 1
  21. #define INPUT_PULLUP 2
  22. inline void pinMode(int16_t pin, uint8_t mode) {}
  23. inline void digitalWrite(int16_t pin, uint8_t value) {
  24. if (auto *p = esphome::gxepd2::PinRegistry::get(pin))
  25. p->digital_write(value != 0);
  26. }
  27. inline int digitalRead(int16_t pin) {
  28. auto *p = esphome::gxepd2::PinRegistry::get(pin);
  29. return (p != nullptr && p->digital_read()) ? HIGH : LOW;
  30. }
  31. // GxEPD2_EPD::_waitWhileBusy() spins on these two (delay() in its main
  32. // branch, yield() right after) for as long as the busy pin stays asserted -
  33. // deliberately up to tens of seconds (_busy_timeout), since a real 3/4-color
  34. // refresh can legitimately take that long. Neither esphome::delay() nor
  35. // esphome::yield() resets the ESP-IDF task watchdog on their own, so
  36. // without an explicit reset here, a real (or a misconfigured-polarity, thus
  37. // permanently "busy") wait outlasts the watchdog and the whole device
  38. // reboots mid-refresh instead of the loop's own timeout ever getting a
  39. // chance to fire.
  40. //
  41. // This calls esp_task_wdt_reset() directly, not esphome::App.feed_wdt():
  42. // feed_wdt()'s rate-limiting state is global, shared by every caller, on
  43. // the assumption only the main loop task ever calls it. This code runs on
  44. // gxepd2's own task (see gxepd2_display.h), so the main loop's frequent
  45. // feed_wdt() calls kept satisfying that shared rate limit and silently
  46. // swallowing this task's - esp_task_wdt_reset() always resets whichever
  47. // task is actually calling it, isn't rate-limited, and is cheap enough to
  48. // call unconditionally here.
  49. inline void delay(uint32_t ms) {
  50. esp_task_wdt_reset();
  51. esphome::delay(ms);
  52. }
  53. inline uint32_t micros() { return esphome::micros(); }
  54. inline void yield() {
  55. esp_task_wdt_reset();
  56. esphome::yield();
  57. }
  58. #define pgm_read_byte(addr) (*reinterpret_cast<const uint8_t *>(addr))
  59. // GxEPD2's per-transfer timing diagnostics are opt-in (this component never
  60. // enables them, by passing serial_diag_bitrate=0 to init()) and stay
  61. // discarded here. But a handful of unconditional warnings - notably
  62. // GxEPD2_EPD::_waitWhileBusy()'s "Busy Timeout!" - also go through Serial,
  63. // and those matter: they're the only signal that the busy pin never
  64. // released. Buffer print() calls and flush to the logger on println(), so
  65. // that warning actually surfaces instead of vanishing silently.
  66. class GxEPD2SerialShim {
  67. public:
  68. void begin(uint32_t baud) {}
  69. template<typename T> void print(T value) { this->buffer_ << value; }
  70. template<typename T> void println(T value) {
  71. this->buffer_ << value;
  72. this->flush_();
  73. }
  74. void println() { this->flush_(); }
  75. private:
  76. void flush_() {
  77. std::string line = this->buffer_.str();
  78. if (!line.empty())
  79. ESP_LOGW("gxepd2", "%s", line.c_str());
  80. this->buffer_.str("");
  81. this->buffer_.clear();
  82. }
  83. std::ostringstream buffer_;
  84. };
  85. inline GxEPD2SerialShim Serial; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)