192 static constexpr std::size_t
WIDTH = 176;
193 static constexpr std::size_t
HEIGHT = 264;
206 std::optional<Device::HalOutput> pwr = std::nullopt)
207 : spi_(spi), cs_(cs), dc_(dc), rst_(rst), busy_(busy), pwr_(std::move(pwr)) {}
216 :
EPD27(device.get_spi(), device.get_output(pins.cs), device.get_output(pins.dc), device.get_output(pins.rst),
217 device.get_input(pins.busy), pins.pwr ? std::make_optional(device.get_output(*pins.pwr)) : std::nullopt) {
232 return std::unexpected(
236 current_mode_ =
mode;
239 if (pwr_.has_value()) {
254 [[nodiscard]]
auto clear() -> std::expected<void, Error> {
259 if (
auto res =
wake(); !res) {
264 const auto width_bytes = (
WIDTH + 7) / 8;
267 for (std::size_t j = 0; j <
HEIGHT; ++j) {
268 for (std::size_t i = 0; i < width_bytes; ++i) {
274 for (std::size_t j = 0; j <
HEIGHT; ++j) {
275 for (std::size_t i = 0; i < width_bytes; ++i) {
285 [[nodiscard]]
auto display(std::span<const std::byte> buffer) -> std::expected<void, Error> {
287 if (
auto res =
wake(); !res) {
293 const auto width_bytes = (
WIDTH + 7) / 8;
295 for (std::size_t j = 0; j <
HEIGHT; ++j) {
296 for (std::size_t i = 0; i < width_bytes; ++i) {
297 const auto index = i + (j * width_bytes);
298 send_data(
static_cast<std::uint8_t
>(buffer[index]));
308 for (std::size_t i = 0; i < total_pixels; ++i) {
309 std::size_t src_idx = i * 2;
310 auto b1 =
static_cast<std::uint8_t
>(buffer[src_idx]);
311 auto b2 =
static_cast<std::uint8_t
>(buffer[src_idx + 1]);
312 send_data(convert_grayscale_pixel(b1, b2,
true));
316 for (std::size_t i = 0; i < total_pixels; ++i) {
317 std::size_t src_idx = i * 2;
318 auto b1 =
static_cast<std::uint8_t
>(buffer[src_idx]);
319 auto b2 =
static_cast<std::uint8_t
>(buffer[src_idx + 1]);
320 send_data(convert_grayscale_pixel(b1, b2,
false));
330 [[nodiscard]]
auto display_planes(std::span<
const std::span<const std::byte>> planes) -> std::expected<void, Error> {
335 if (
auto res =
wake(); !res) {
339 if (planes.empty()) {
348 [[nodiscard]]
auto sleep() -> std::expected<void, Error> {
366 [[nodiscard]]
auto wake() -> std::expected<void, Error> {
370 return init(current_mode_);
373 [[nodiscard]]
auto power_off() -> std::expected<void, Error> {
382 [[nodiscard]]
auto power_on() -> std::expected<void, Error> {
391 [[nodiscard]]
static auto width() noexcept -> std::
size_t {
return WIDTH; }
392 [[nodiscard]]
static auto height() noexcept -> std::
size_t {
return HEIGHT; }
404 [[nodiscard]]
static auto supports_wake() noexcept ->
bool {
return false; }
412 std::optional<Device::HalOutput> pwr_;
414 bool initialized_ =
false;
415 bool is_asleep_ =
false;
426 void send_command(
Command command) {
429 spi_.
transfer(
static_cast<std::uint8_t
>(command));
433 void send_data(std::uint8_t data) {
446 void wait_busy_simple() {
448 while (busy_.
read() && iterations < 100) {
453 while (!busy_.
read() && iterations < 1000) {
510 void init_grayscale() {
564 static constexpr std::array<std::uint8_t, 44> LUT_VCOM_DC = {
565 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x60, 0x28, 0x28, 0x00, 0x00, 0x01, 0x00,
566 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
569 static constexpr std::array<std::uint8_t, 42> LUT_WW = {
570 0x40, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x40, 0x14,
571 0x00, 0x00, 0x00, 0x01, 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
574 static constexpr std::array<std::uint8_t, 42> LUT_BW = {
575 0x40, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x40, 0x14,
576 0x00, 0x00, 0x00, 0x01, 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
579 static constexpr std::array<std::uint8_t, 42> LUT_BB = {
580 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x80, 0x14,
581 0x00, 0x00, 0x00, 0x01, 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
582 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
584 static constexpr std::array<std::uint8_t, 42> LUT_WB = {
585 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x80, 0x14,
586 0x00, 0x00, 0x00, 0x01, 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
590 static constexpr std::array<std::uint8_t, 44> LUT_VCOM_GRAY = {
591 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x60, 0x14, 0x14, 0x00, 0x00, 0x01, 0x00,
592 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x13, 0x0A, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
595 static constexpr std::array<std::uint8_t, 42> LUT_WW_GRAY = {
596 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, 0x10, 0x14,
597 0x0A, 0x00, 0x00, 0x01, 0xA0, 0x13, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
600 static constexpr std::array<std::uint8_t, 42> LUT_BW_GRAY = {
601 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, 0x00, 0x14,
602 0x0A, 0x00, 0x00, 0x01, 0x99, 0x0C, 0x01, 0x03, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
605 static constexpr std::array<std::uint8_t, 42> LUT_WB_GRAY = {
606 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, 0x00, 0x14,
607 0x0A, 0x00, 0x00, 0x01, 0x99, 0x0B, 0x04, 0x04, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
610 static constexpr std::array<std::uint8_t, 42> LUT_BB_GRAY = {
611 0x80, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, 0x20, 0x14,
612 0x0A, 0x00, 0x00, 0x01, 0x50, 0x13, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
617 for (
auto b : LUT_VCOM_DC) {
638 void set_lut_grayscale() {
640 for (
auto b : LUT_VCOM_GRAY) {
644 for (
auto b : LUT_WW_GRAY) {
648 for (
auto b : LUT_BW_GRAY) {
652 for (
auto b : LUT_WB_GRAY) {
656 for (
auto b : LUT_BB_GRAY) {
660 for (
auto b : LUT_WW_GRAY) {
665 static auto convert_grayscale_pixel(std::uint8_t byte1, std::uint8_t byte2,
bool is_old_data) -> std::uint8_t {
666 std::uint8_t result = 0;
667 for (std::size_t j = 0; j < 2; ++j) {
668 auto temp1 = (j == 0) ? byte1 : byte2;
669 for (std::size_t k = 0; k < 4; ++k) {