idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
gray4_framebuffer.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
13#include <idfxx/epaper/color>
14#include <idfxx/epaper/panel>
15#include <idfxx/error>
16
17#include <algorithm>
18#include <cstddef>
19#include <cstdint>
20#include <span>
21#include <utility>
22#include <vector>
23
28namespace idfxx::epaper {
29
59public:
62
63#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
73 [[nodiscard]] gray4_framebuffer(size_t width, size_t height)
75#endif
76
86 [[nodiscard]] static result<gray4_framebuffer> make(size_t width, size_t height) {
87 if (width == 0 || height == 0) {
89 }
90 // Both planes live in one allocation: plane 0 first, then plane 1.
91 return gray4_framebuffer{width, height, std::vector<uint8_t>(2 * ((width + 7) / 8) * height)};
92 }
93
95 [[nodiscard]] size_t width() const noexcept { return _width; }
96
98 [[nodiscard]] size_t height() const noexcept { return _height; }
99
108 [[nodiscard]] size_t stride_bytes() const noexcept { return (_width + 7) / 8; }
109
119 void set_pixel(size_t x, size_t y, gray4 level) noexcept {
120 if (x >= _width || y >= _height) {
121 return;
122 }
123 const size_t index = y * stride_bytes() + x / 8;
124 const uint8_t mask = static_cast<uint8_t>(1u << (7 - x % 8));
125 const auto bits = std::to_underlying(level);
126 _set_plane_bit(_data[index], mask, (bits & 0x01) != 0);
127 _set_plane_bit(_data[_plane_size() + index], mask, (bits & 0x02) != 0);
128 }
129
138 [[nodiscard]] gray4 get_pixel(size_t x, size_t y) const noexcept {
139 if (x >= _width || y >= _height) {
140 return gray4::white;
141 }
142 const size_t index = y * stride_bytes() + x / 8;
143 const uint8_t mask = static_cast<uint8_t>(1u << (7 - x % 8));
144 uint8_t bits = 0;
145 if ((_data[index] & mask) != 0) {
146 bits |= 0x01;
147 }
148 if ((_data[_plane_size() + index] & mask) != 0) {
149 bits |= 0x02;
150 }
151 return static_cast<gray4>(bits);
152 }
153
158 void fill(gray4 level) noexcept {
159 const auto bits = std::to_underlying(level);
160 auto plane0 = std::span<uint8_t>(_data).first(_plane_size());
161 auto plane1 = std::span<uint8_t>(_data).last(_plane_size());
162 std::ranges::fill(plane0, (bits & 0x01) != 0 ? uint8_t{0xFF} : uint8_t{0x00});
163 std::ranges::fill(plane1, (bits & 0x02) != 0 ? uint8_t{0xFF} : uint8_t{0x00});
164 }
165
167 void clear() noexcept { fill(gray4::white); }
168
182 [[nodiscard]] std::span<const uint8_t> plane(size_t index) const noexcept {
183 return std::span<const uint8_t>(_data).subspan(index * _plane_size(), _plane_size());
184 }
185
196 [[nodiscard]] std::span<const uint8_t> plane_row(size_t index, size_t y) const noexcept {
197 return plane(index).subspan(y * stride_bytes(), stride_bytes());
198 }
199
200#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
214 void flush(panel& panel, size_t x = 0, size_t y = 0) const { unwrap(try_flush(panel, x, y)); }
215
230 void flush_rows(panel& panel, size_t y_start, size_t y_end) const { unwrap(try_flush_rows(panel, y_start, y_end)); }
231#endif
232
245 [[nodiscard]] result<void> try_flush(panel& panel, size_t x = 0, size_t y = 0) const {
246 return panel.try_write(*this, x, y);
247 }
248
263 [[nodiscard]] result<void> try_flush_rows(panel& panel, size_t y_start, size_t y_end) const {
264 return panel.try_write_rows(*this, y_start, y_end);
265 }
266
267private:
268 gray4_framebuffer(size_t width, size_t height, std::vector<uint8_t> data)
269 : _width(width)
270 , _height(height)
271 , _data(std::move(data)) {}
272
273 [[nodiscard]] size_t _plane_size() const noexcept { return stride_bytes() * _height; }
274
275 static void _set_plane_bit(uint8_t& byte, uint8_t mask, bool on) noexcept {
276 if (on) {
277 byte |= mask;
278 } else {
279 byte &= static_cast<uint8_t>(~mask);
280 }
281 }
282
283 size_t _width;
284 size_t _height;
285 std::vector<uint8_t> _data; // plane 0 followed by plane 1
286};
287
288} // namespace idfxx::epaper
In-memory framebuffer for 4-level grayscale ePaper displays.
void fill(gray4 level) noexcept
Sets every pixel to the given gray level.
size_t height() const noexcept
Returns the height in pixels.
result< void > try_flush_rows(panel &panel, size_t y_start, size_t y_end) const
Uploads a horizontal band of the framebuffer to a panel's RAM.
size_t width() const noexcept
Returns the width in pixels.
void flush_rows(panel &panel, size_t y_start, size_t y_end) const
Uploads a horizontal band of the framebuffer to a panel's RAM.
void flush(panel &panel, size_t x=0, size_t y=0) const
Uploads the full framebuffer to a panel's RAM.
gray4_framebuffer(size_t width, size_t height)
Creates a framebuffer of the given dimensions, with all pixels white.
std::span< const uint8_t > plane(size_t index) const noexcept
Returns the raw pixel data of one plane.
gray4 get_pixel(size_t x, size_t y) const noexcept
Returns the gray level of a single pixel.
size_t stride_bytes() const noexcept
Returns the number of bytes per row within each plane.
std::span< const uint8_t > plane_row(size_t index, size_t y) const noexcept
Returns the raw bytes of a single row of one plane.
static result< gray4_framebuffer > make(size_t width, size_t height)
Creates a framebuffer of the given dimensions, with all pixels white.
void clear() noexcept
Blanks every pixel to white (equivalent to fill(gray4::white)).
result< void > try_flush(panel &panel, size_t x=0, size_t y=0) const
Uploads the full framebuffer to a panel's RAM.
void set_pixel(size_t x, size_t y, gray4 level) noexcept
Sets a single pixel to the given gray level.
Abstract base class for ePaper display panels.
Definition panel.hpp:116
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.
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.
ePaper display driver classes.
Definition color.hpp:19
gray4
A 4-level grayscale pixel value.
Definition color.hpp:30
@ white
Blank paper (no ink).
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_arg
Invalid argument.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
Definition error.hpp:120