idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
panel.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
34#include <idfxx/error>
35#include <idfxx/gpio>
36
37#include <chrono>
38#include <cstddef>
39#include <cstdint>
40#include <optional>
41
46namespace idfxx::epaper {
47
48class mono_framebuffer;
49class gray4_framebuffer;
50
58enum class refresh_mode : uint8_t {
62 full,
66 fast,
71 partial,
72};
73
81enum class color_mode : uint8_t {
82 mono,
83 gray4,
84};
85
116class panel {
117public:
118 virtual ~panel() = default;
119
120 panel(const panel&) = delete;
121 panel& operator=(const panel&) = delete;
122
123 // =========================================================================
124 // Accessors
125 // =========================================================================
126
128 [[nodiscard]] size_t width() const noexcept { return _width; }
129
131 [[nodiscard]] size_t height() const noexcept { return _height; }
132
141 [[nodiscard]] enum color_mode color_mode() const noexcept { return _color_mode; }
142
152 [[nodiscard]] bool asleep() const noexcept { return _asleep; }
153
154 // =========================================================================
155 // RAM upload
156 // =========================================================================
157
158#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
176 void write(const mono_framebuffer& fb, size_t x = 0, size_t y = 0) { unwrap(try_write(fb, x, y)); }
177
195 void write(const gray4_framebuffer& fb, size_t x = 0, size_t y = 0) { unwrap(try_write(fb, x, y)); }
196
218 void write_rows(const mono_framebuffer& fb, size_t row_start, size_t row_end, size_t x = 0, size_t y = 0) {
219 unwrap(try_write_rows(fb, row_start, row_end, x, y));
220 }
221
242 void write_rows(const gray4_framebuffer& fb, size_t row_start, size_t row_end, size_t x = 0, size_t y = 0) {
243 unwrap(try_write_rows(fb, row_start, row_end, x, y));
244 }
245
263 void clear() { unwrap(try_clear()); }
264#endif
265
283 [[nodiscard]] result<void> try_write(const mono_framebuffer& fb, size_t x = 0, size_t y = 0);
284
302 [[nodiscard]] result<void> try_write(const gray4_framebuffer& fb, size_t x = 0, size_t y = 0);
303
325 [[nodiscard]] result<void>
326 try_write_rows(const mono_framebuffer& fb, size_t row_start, size_t row_end, size_t x = 0, size_t y = 0);
327
348 [[nodiscard]] result<void>
349 try_write_rows(const gray4_framebuffer& fb, size_t row_start, size_t row_end, size_t x = 0, size_t y = 0);
350
367 [[nodiscard]] result<void> try_clear() {
368 if (_asleep) {
370 }
371 if (auto r = do_clear(); !r) {
372 return r;
373 }
374 _has_baseline = false;
375 return {};
376 }
377
378 // =========================================================================
379 // Refresh
380 // =========================================================================
381
382#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
404
417 void wait() { unwrap(try_wait()); }
418
431 template<typename Rep, typename Period>
432 void wait_for(const std::chrono::duration<Rep, Period>& timeout) {
434 }
435#endif
436
459 if (_asleep) {
461 }
462 if (mode == refresh_mode::partial && !_has_baseline) {
463 mode = refresh_mode::full;
464 }
465 if (auto r = do_refresh(mode); !r) {
466 return r;
467 }
468 _has_baseline = true;
469 return {};
470 }
471
483 [[nodiscard]] result<void> try_wait() { return do_wait(std::nullopt); }
484
496 template<typename Rep, typename Period>
497 [[nodiscard]] result<void> try_wait_for(const std::chrono::duration<Rep, Period>& timeout) {
498 return do_wait(std::chrono::ceil<std::chrono::milliseconds>(timeout));
499 }
500
501 // =========================================================================
502 // Color mode
503 // =========================================================================
504
505#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
521#endif
522
536 [[nodiscard]] result<void> try_set_color_mode(enum color_mode mode) {
537 if (_asleep) {
539 }
540 if (mode == _color_mode) {
541 return {};
542 }
543 if (auto r = do_set_color_mode(mode); !r) {
544 return r;
545 }
546 _color_mode = mode;
547 _has_baseline = false;
548 return {};
549 }
550
551 // =========================================================================
552 // Power management
553 // =========================================================================
554
555#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
569 void sleep() { unwrap(try_sleep()); }
570
584 void wake() { unwrap(try_wake()); }
585#endif
586
600 if (_asleep) {
601 return {};
602 }
603 if (auto r = do_sleep(); !r) {
604 return r;
605 }
606 _asleep = true;
607 return {};
608 }
609
622 [[nodiscard]] result<void> try_wake() {
623 if (auto r = do_wake(); !r) {
624 return r;
625 }
626 _asleep = false;
627 _has_baseline = false;
628 return {};
629 }
630
631protected:
642 panel(size_t width, size_t height) noexcept
643 : _width(width)
644 , _height(height) {}
645
663 size_t width,
664 size_t height,
666 enum gpio::level busy_level,
667 std::chrono::milliseconds busy_timeout,
669 ) noexcept
670 : _width(width)
671 , _height(height)
672 , _busy_gpio(busy_gpio)
673 , _busy_level(busy_level)
674 , _busy_timeout(busy_timeout)
675 , _reset_gpio(reset_gpio) {}
676
677 panel(panel&&) noexcept = default;
678 panel& operator=(panel&&) noexcept = default;
679
681 [[nodiscard]] gpio busy_gpio() const noexcept { return _busy_gpio; }
682
684 [[nodiscard]] gpio reset_gpio() const noexcept { return _reset_gpio; }
685
687 [[nodiscard]] std::chrono::milliseconds busy_timeout() const noexcept { return _busy_timeout; }
688
689 // =========================================================================
690 // Customization hooks
691 //
692 // Concrete drivers override these (typically privately). Each hook
693 // implements the correspondingly named public method; validation common
694 // to all controllers (alignment, bounds, sleep state, color-mode match,
695 // partial-refresh baseline promotion) has already been performed by the
696 // public wrappers.
697 // =========================================================================
698
705 [[nodiscard]] virtual result<void>
706 do_write(const mono_framebuffer& fb, size_t row_start, size_t row_end, size_t x, size_t y) = 0;
716 [[nodiscard]] virtual result<void>
717 do_write(const gray4_framebuffer& fb, size_t row_start, size_t row_end, size_t x, size_t y) {
718 (void)fb;
719 (void)row_start;
720 (void)row_end;
721 (void)x;
722 (void)y;
724 }
725
729 [[nodiscard]] virtual result<void> do_clear() = 0;
730
736 [[nodiscard]] virtual result<void> do_refresh(refresh_mode mode) = 0;
737
741 [[nodiscard]] virtual result<void> do_set_color_mode(enum color_mode mode) {
742 (void)mode;
744 }
745
747 [[nodiscard]] virtual result<void> do_sleep() = 0;
750 [[nodiscard]] virtual result<void> do_wake() = 0;
751
755 [[nodiscard]] virtual result<void> do_wait(std::optional<std::chrono::milliseconds> timeout) {
756 return wait_busy(timeout);
757 }
758
772
786 [[nodiscard]] result<void> wait_busy(std::optional<std::chrono::milliseconds> timeout = std::nullopt);
787
799
800private:
801 template<typename FB>
802 [[nodiscard]] result<void>
803 _try_write_rows(const FB& fb, enum color_mode expected, size_t row_start, size_t row_end, size_t x, size_t y);
804
805 size_t _width;
806 size_t _height;
807 gpio _busy_gpio = gpio::nc();
808 enum gpio::level _busy_level = gpio::level::high;
809 std::chrono::milliseconds _busy_timeout{15'000};
810 gpio _reset_gpio = gpio::nc();
811 enum color_mode _color_mode = color_mode::mono;
812 bool _asleep = false;
813 // Whether the controller holds a refreshed image a partial update can
814 // diff against; cleared by wake and color-mode changes.
815 bool _has_baseline = false;
816};
817
818} // namespace idfxx::epaper
819
// end of idfxx_epaper
In-memory framebuffer for 4-level grayscale ePaper displays.
In-memory framebuffer for monochrome (1 bit per pixel) ePaper displays.
Abstract base class for ePaper display panels.
Definition panel.hpp:116
result< void > try_set_color_mode(enum color_mode mode)
Switches the panel between monochrome and grayscale operation.
Definition panel.hpp:536
result< void > try_clear()
Clears the controller's RAM to white, without a framebuffer.
Definition panel.hpp:367
void write_rows(const gray4_framebuffer &fb, size_t row_start, size_t row_end, size_t x=0, size_t y=0)
Uploads a horizontal band of a grayscale framebuffer.
Definition panel.hpp:242
bool asleep() const noexcept
Returns whether the panel is in deep sleep.
Definition panel.hpp:152
virtual result< void > do_set_color_mode(enum color_mode mode)
Hook for try_set_color_mode.
Definition panel.hpp:741
void sleep()
Puts the panel controller into deep sleep.
Definition panel.hpp:569
result< void > hardware_reset()
Pulses the reset line and waits for the controller to settle.
std::chrono::milliseconds busy_timeout() const noexcept
Returns the default BUSY timeout.
Definition panel.hpp:687
result< void > try_sleep()
Puts the panel controller into deep sleep.
Definition panel.hpp:599
result< void > wait_busy(std::optional< std::chrono::milliseconds > timeout=std::nullopt)
Polls the BUSY line until it releases.
void write(const gray4_framebuffer &fb, size_t x=0, size_t y=0)
Uploads a grayscale framebuffer to the controller's RAM.
Definition panel.hpp:195
result< void > try_wake()
Wakes the panel controller from deep sleep.
Definition panel.hpp:622
virtual ~panel()=default
void wait_for(const std::chrono::duration< Rep, Period > &timeout)
Waits for the controller's BUSY line to release, with a timeout.
Definition panel.hpp:432
virtual result< void > do_clear()=0
Hook for try_clear.
virtual result< void > do_sleep()=0
Hook for try_sleep. Called only while the panel is awake.
void wait()
Waits for the controller's BUSY line to release.
Definition panel.hpp:417
void write_rows(const mono_framebuffer &fb, size_t row_start, size_t row_end, size_t x=0, size_t y=0)
Uploads a horizontal band of a monochrome framebuffer.
Definition panel.hpp:218
result< void > try_write(const gray4_framebuffer &fb, size_t x=0, size_t y=0)
Uploads a grayscale framebuffer to the controller's RAM.
size_t height() const noexcept
Returns the panel height in pixels.
Definition panel.hpp:131
static result< void > configure_control_lines(gpio busy_gpio, gpio reset_gpio)
Configures the direction of the BUSY and reset pins.
result< void > try_write(const mono_framebuffer &fb, size_t x=0, size_t y=0)
Uploads a monochrome framebuffer to the controller's RAM.
virtual result< void > do_write(const mono_framebuffer &fb, size_t row_start, size_t row_end, size_t x, size_t y)=0
Hook for try_write / try_write_rows (monochrome).
result< void > try_refresh(refresh_mode mode=refresh_mode::full)
Refreshes the panel from the controller's RAM.
Definition panel.hpp:458
panel(panel &&) noexcept=default
gpio reset_gpio() const noexcept
Returns the reset output pin (may be unconnected).
Definition panel.hpp:684
result< void > try_wait_for(const std::chrono::duration< Rep, Period > &timeout)
Waits for the controller's BUSY line to release, with a timeout.
Definition panel.hpp:497
virtual result< void > do_wait(std::optional< std::chrono::milliseconds > timeout)
Hook for try_wait / try_wait_for.
Definition panel.hpp:755
void set_color_mode(enum color_mode mode)
Switches the panel between monochrome and grayscale operation.
Definition panel.hpp:520
result< void > try_write_rows(const gray4_framebuffer &fb, size_t row_start, size_t row_end, size_t x=0, size_t y=0)
Uploads a horizontal band of a grayscale framebuffer.
virtual result< void > do_wake()=0
Hook for try_wake.
panel(const panel &)=delete
result< void > try_write_rows(const mono_framebuffer &fb, size_t row_start, size_t row_end, size_t x=0, size_t y=0)
Uploads a horizontal band of a monochrome framebuffer.
panel(size_t width, size_t height, gpio busy_gpio, enum gpio::level busy_level, std::chrono::milliseconds busy_timeout, gpio reset_gpio) noexcept
Constructs the panel base with the given dimensions and control lines.
Definition panel.hpp:662
gpio busy_gpio() const noexcept
Returns the BUSY input pin (may be unconnected).
Definition panel.hpp:681
result< void > try_wait()
Waits for the controller's BUSY line to release.
Definition panel.hpp:483
enum color_mode color_mode() const noexcept
Returns the panel's current pixel format.
Definition panel.hpp:141
virtual result< void > do_refresh(refresh_mode mode)=0
Hook for try_refresh.
panel(size_t width, size_t height) noexcept
Constructs the panel base with the given dimensions and no control lines.
Definition panel.hpp:642
panel & operator=(const panel &)=delete
void write(const mono_framebuffer &fb, size_t x=0, size_t y=0)
Uploads a monochrome framebuffer to the controller's RAM.
Definition panel.hpp:176
void wake()
Wakes the panel controller from deep sleep.
Definition panel.hpp:584
virtual result< void > do_write(const gray4_framebuffer &fb, size_t row_start, size_t row_end, size_t x, size_t y)
Hook for try_write / try_write_rows (grayscale).
Definition panel.hpp:717
size_t width() const noexcept
Returns the panel width in pixels.
Definition panel.hpp:128
void clear()
Clears the controller's RAM to white, without a framebuffer.
Definition panel.hpp:263
void refresh(refresh_mode mode=refresh_mode::full)
Refreshes the panel from the controller's RAM.
Definition panel.hpp:403
A GPIO pin.
Definition gpio.hpp:62
static constexpr gpio nc()
Returns a GPIO representing "not connected".
Definition gpio.hpp:255
level
GPIO output/input level.
Definition gpio.hpp:68
@ high
Logic high (1)
ePaper display driver classes.
Definition color.hpp:19
refresh_mode
Refresh style for panel::refresh.
Definition panel.hpp:58
@ partial
Differential update: only pixels that changed since the previous refresh flip, without the full-refre...
@ fast
Full-screen update with a shortened waveform: much faster than refresh_mode::full and still updates e...
@ full
Full update with the controller's highest-quality waveform: the panel flashes through inverse images ...
color_mode
Pixel format the panel is operating in.
Definition panel.hpp:81
@ mono
1 bit per pixel black-and-white (mono_framebuffer).
gray4
A 4-level grayscale pixel value.
Definition color.hpp:30
constexpr std::unexpected< std::error_code > error(E e) noexcept
Creates an unexpected error from an error code enum.
Definition error.hpp:187
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
Definition error.hpp:307
@ invalid_state
Invalid state.
@ timeout
Operation timed out.
@ not_supported
Operation or feature not supported.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
Definition error.hpp:120