From 43840e3ba1ef777d7082d34d2f80a9812cbd7855 Mon Sep 17 00:00:00 2001 From: lovyan03 <42724151+lovyan03@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:52:21 +0900 Subject: [PATCH] Add Panel_EPDiy --- src/lgfx/v1/panel/Panel_EPDiy.cpp | 322 +++++++++++++++++++++++++ src/lgfx/v1/panel/Panel_EPDiy.hpp | 87 +++++++ src/lgfx/v1/platforms/esp32/common.cpp | 2 +- 3 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 src/lgfx/v1/panel/Panel_EPDiy.cpp create mode 100644 src/lgfx/v1/panel/Panel_EPDiy.hpp diff --git a/src/lgfx/v1/panel/Panel_EPDiy.cpp b/src/lgfx/v1/panel/Panel_EPDiy.cpp new file mode 100644 index 00000000..5e38c27e --- /dev/null +++ b/src/lgfx/v1/panel/Panel_EPDiy.cpp @@ -0,0 +1,322 @@ +/*----------------------------------------------------------------------------/ + Lovyan GFX - Graphics library for embedded devices. + +Original Source: + https://github.com/lovyan03/LovyanGFX/ + +Licence: + [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt) + +Author: + [lovyan03](https://twitter.com/lovyan03) + +Contributors: + [ciniml](https://github.com/ciniml) + [mongonta0716](https://github.com/mongonta0716) + [tobozo](https://github.com/tobozo) +/----------------------------------------------------------------------------*/ + +#if __has_include () +extern "C" { + #include +}; + +#include "Panel_EPDiy.hpp" +#include "lgfx/v1/Bus.hpp" +#include "lgfx/v1/platforms/common.hpp" +#include "lgfx/v1/misc/pixelcopy.hpp" +#include "lgfx/v1/misc/colortype.hpp" + +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif + +namespace lgfx +{ + inline namespace v1 + { +//---------------------------------------------------------------------------- + + static constexpr int8_t Bayer[16] = {-30, 2, -22, 10, 18, -14, 26, -6, -18, 14, -26, 6, 30, -2, 22, -10}; + + Panel_EPDiy::Panel_EPDiy(void) + { + _epd_mode = epd_mode_t::epd_quality; + _auto_display = true; + } + + Panel_EPDiy::~Panel_EPDiy(void) + { + } + + color_depth_t Panel_EPDiy::setColorDepth(color_depth_t depth) + { + _write_depth = color_depth_t::rgb888_3Byte; + _read_depth = color_depth_t::rgb888_3Byte; + return depth; + } + + bool Panel_EPDiy::init(bool use_reset) + { + Panel_HasBuffer::init(use_reset); + + epd_set_board(_config_detail.epd_board); + + _buf = epd_hl_get_framebuffer(_config_detail.epd_hl); + + startWrite(); + memset(_buf, 0, _cfg.memory_width * _cfg.memory_height / 2); + display(0, 0, _cfg.panel_width, _cfg.panel_height); + memset(_buf, 0xFF, _cfg.memory_width * _cfg.memory_height / 2); + display(0, 0, _cfg.panel_width, _cfg.panel_height); + endWrite(); + + return true; + } + + void Panel_EPDiy::beginTransaction(void) + { + epd_set_board(_config_detail.epd_board); + epd_poweron(); + } + + void Panel_EPDiy::endTransaction(void) + { + epd_poweroff(); + } + + void Panel_EPDiy::waitDisplay(void) + { + } + + bool Panel_EPDiy::displayBusy(void) + { + return false; + } + + void Panel_EPDiy::setInvert(bool invert) + { + // unimplemented + _invert = invert; + } + + void Panel_EPDiy::setSleep(bool flg) + { + } + + void Panel_EPDiy::setPowerSave(bool flg) + { + } + + void Panel_EPDiy::writeFillRectPreclipped(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, uint32_t rawcolor) + { + uint_fast16_t xs = x, xe = x + w - 1; + uint_fast16_t ys = y, ye = y + h - 1; + _xs = xs; + _ys = ys; + _xe = xe; + _ye = ye; + _update_transferred_rect(xs, ys, xe, ye); + + bgr888_t color { rawcolor }; + int32_t sum = (color.R8() + (color.G8() << 1) + color.B8()); + + bool fast = _epd_mode == epd_mode_t::epd_fast || _epd_mode == epd_mode_t::epd_fastest; + y = ys; + do + { + x = xs; + auto btbl = &Bayer[(y & 3) << 2]; + auto buf = &_buf[y * ((_cfg.panel_width + 1) >> 1)]; + + if (fast) { + do + { + size_t idx = x >> 1; + uint_fast8_t shift = (x & 1) ? 4 : 0; + uint_fast8_t value = (sum + btbl[x & 3] * 16 < 512 ? 0 : 0xF) << shift; + buf[idx] = (buf[idx] & (0xF0 >> shift)) | value; + } while (++x <= xe); + } else { + do + { + size_t idx = x >> 1; + uint_fast8_t shift = (x & 1) ? 4 : 0; + uint_fast8_t value = (std::min(15, std::max(0, sum + btbl[x & 3]) >> 6) & 0x0F) << shift; + buf[idx] = (buf[idx] & (0xF0 >> shift)) | value; + } while (++x <= xe); + } + } while (++y <= ye); + } + + void Panel_EPDiy::writeImage(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, pixelcopy_t* param, bool use_dma) + { + uint_fast16_t xs = x, xe = x + w - 1; + uint_fast16_t ys = y, ye = y + h - 1; + _update_transferred_rect(xs, ys, xe, ye); + + auto readbuf = (bgr888_t*)alloca(w * sizeof(bgr888_t)); + auto sx = param->src_x32; + h += y; + do + { + uint32_t prev_pos = 0, new_pos = 0; + do + { + new_pos = param->fp_copy(readbuf, prev_pos, w, param); + if (new_pos != prev_pos) + { + do + { + auto color = readbuf[prev_pos]; + _draw_pixel(x + prev_pos, y, (color.R8() + (color.G8() << 1) + color.B8())); + } while (new_pos != ++prev_pos); + } + } while (w != new_pos && w != (prev_pos = param->fp_skip(new_pos, w, param))); + param->src_x32 = sx; + param->src_y++; + } while (++y < h); + } + + void Panel_EPDiy::writePixels(pixelcopy_t* param, uint32_t length, bool use_dma) + { + { + uint_fast16_t xs = _xs; + uint_fast16_t xe = _xe; + uint_fast16_t ys = _ys; + uint_fast16_t ye = _ye; + _update_transferred_rect(xs, ys, xe, ye); + } + uint_fast16_t xs = _xs ; + uint_fast16_t ys = _ys ; + uint_fast16_t xe = _xe ; + uint_fast16_t ye = _ye ; + uint_fast16_t xpos = _xpos; + uint_fast16_t ypos = _ypos; + + static constexpr uint32_t buflen = 16; + bgr888_t colors[buflen]; + int bufpos = buflen; + do + { + if (bufpos == buflen) { + param->fp_copy(colors, 0, std::min(length, buflen), param); + bufpos = 0; + } + auto color = colors[bufpos++]; + _draw_pixel(xpos, ypos, (color.R8() + (color.G8() << 1) + color.B8())); + if (++xpos > xe) + { + xpos = xs; + if (++ypos > ye) + { + ypos = ys; + } + } + } while (--length); + _xpos = xpos; + _ypos = ypos; + } + + void Panel_EPDiy::readRect(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, void* __restrict dst, pixelcopy_t* param) + { + auto readbuf = (bgr888_t*)alloca(w * sizeof(bgr888_t)); + param->src_data = readbuf; + int32_t readpos = 0; + h += y; + do + { + uint32_t idx = 0; + do + { + readbuf[idx] = 0x010101u * (_read_pixel(x + idx, y) * 16 + 8); + } while (++idx != w); + param->src_x32 = 0; + readpos = param->fp_copy(dst, readpos, readpos + w, param); + } while (++y < h); + } + + void Panel_EPDiy::_draw_pixel(uint_fast16_t x, uint_fast16_t y, uint32_t sum) + { + _rotate_pos(x, y); + + auto btbl = &Bayer[(y & 3) << 2]; + size_t idx = (x >> 1) + (y * ((_cfg.panel_width + 1) >> 1)); + uint_fast8_t shift = (x & 1) ? 4 : 0; + uint_fast8_t value; + bool fast = _epd_mode == epd_mode_t::epd_fast || _epd_mode == epd_mode_t::epd_fastest; + if (fast) { + value = (sum + btbl[x & 3] * 16 < 512 ? 0 : 0xF) << shift; + } else { + value = (std::min(15, std::max(0, sum + btbl[x & 3]) >> 6) & 0x0F) << shift; + } + _buf[idx] = (_buf[idx] & (0xF0 >> shift)) | value; + } + + uint8_t Panel_EPDiy::_read_pixel(uint_fast16_t x, uint_fast16_t y) + { + _rotate_pos(x, y); + size_t idx = (x >> 1) + (y * ((_cfg.panel_width + 1) >> 1)); + return (x & 1) + ? (_buf[idx] >> 4) + : (_buf[idx] & 0x0F) + ; + } + + void Panel_EPDiy::_update_transferred_rect(uint_fast16_t &xs, uint_fast16_t &ys, uint_fast16_t &xe, uint_fast16_t &ye) + { + _rotate_pos(xs, ys, xe, ye); + _range_mod.left = std::min(xs, _range_mod.left); + _range_mod.right = std::max(xe, _range_mod.right); + _range_mod.top = std::min(ys, _range_mod.top); + _range_mod.bottom = std::max(ye, _range_mod.bottom); + } + + void Panel_EPDiy::display(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h) + { + if (0 < w && 0 < h) + { + _range_mod.left = std::min(_range_mod.left , x ); + _range_mod.right = std::max(_range_mod.right , x + w - 1); + _range_mod.top = std::min(_range_mod.top , y ); + _range_mod.bottom = std::max(_range_mod.bottom, y + h - 1); + } + + if (_range_mod.empty()) { return; } + + uint_fast16_t xs = (_range_mod.left + _cfg.offset_x) & ~ 3; + uint_fast16_t xe = (_range_mod.right + _cfg.offset_x + 3) & ~ 3; + uint_fast16_t ys = _range_mod.top + _cfg.offset_y; + uint_fast16_t ye = _range_mod.bottom + _cfg.offset_y; + + EpdRect area; + area.x = xs; + area.y = ys; + area.width = xe - xs + 1; + area.height = ye - ys + 1; + + EpdDrawMode mode; + switch (_epd_mode) + { + // case epd_mode_t::epd_fastest: mode = EpdDrawMode::MODE_DU4; break; + case epd_mode_t::epd_fastest: mode = EpdDrawMode::MODE_DU; break; // TODO: check DU4 mode + case epd_mode_t::epd_fast: mode = EpdDrawMode::MODE_DU; break; + case epd_mode_t::epd_text: mode = EpdDrawMode::MODE_GL16; break; + default: mode = EpdDrawMode::MODE_GC16; break; + } + epd_hl_update_area(_config_detail.epd_hl, mode, epd_ambient_temperature(), area); + + _range_mod.top = INT16_MAX; + _range_mod.left = INT16_MAX; + _range_mod.right = 0; + _range_mod.bottom = 0; + } + +//---------------------------------------------------------------------------- + } +} +#endif + diff --git a/src/lgfx/v1/panel/Panel_EPDiy.hpp b/src/lgfx/v1/panel/Panel_EPDiy.hpp new file mode 100644 index 00000000..326eecc3 --- /dev/null +++ b/src/lgfx/v1/panel/Panel_EPDiy.hpp @@ -0,0 +1,87 @@ +/*----------------------------------------------------------------------------/ + Lovyan GFX - Graphics library for embedded devices. + +Original Source: + https://github.com/lovyan03/LovyanGFX/ + +Licence: + [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt) + +Author: + [lovyan03](https://twitter.com/lovyan03) + +Contributors: + [ciniml](https://github.com/ciniml) + [mongonta0716](https://github.com/mongonta0716) + [tobozo](https://github.com/tobozo) +/----------------------------------------------------------------------------*/ +#pragma once + +#if __has_include () +extern "C" { + #include +}; +#endif + +#include "lgfx/v1/panel/Panel_HasBuffer.hpp" +#include "lgfx/v1/misc/range.hpp" + +namespace lgfx +{ + inline namespace v1 + { +//---------------------------------------------------------------------------- + + struct Panel_EPDiy : public Panel_HasBuffer + { + Panel_EPDiy(void); + virtual ~Panel_EPDiy(void); + + struct config_detail_t + { +#if __has_include () + EpdBoardDefinition* epd_board; + EpdiyHighlevelState* epd_hl; +#endif + }; + + const config_detail_t& config_detail(void) const { return _config_detail; } + void config_detail(const config_detail_t& config_detail) { _config_detail = config_detail; } + + void beginTransaction(void) override; + void endTransaction(void) override; + + bool init(bool use_reset) override; + + void waitDisplay(void) override; + bool displayBusy(void) override; + color_depth_t setColorDepth(color_depth_t depth) override; + + void setInvert(bool invert) override; + void setSleep(bool flg) override; + void setPowerSave(bool flg) override; + + void display(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h) override; + + void writeFillRectPreclipped(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, uint32_t rawcolor) override; + void writeImage(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, pixelcopy_t* param, bool use_dma) override; + void writePixels(pixelcopy_t* param, uint32_t len, bool use_dma) override; + + uint32_t readCommand(uint_fast16_t, uint_fast8_t, uint_fast8_t) override { return 0; } + uint32_t readData(uint_fast8_t, uint_fast8_t) override { return 0; } + + void readRect(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, void* dst, pixelcopy_t* param) override; + + private: + config_detail_t _config_detail; + + // フレームバッファはEPDiyに用意してもらうのでここでの戻り値は0とする + size_t _get_buffer_length(void) const override { return 0; } + uint8_t _read_pixel(uint_fast16_t x, uint_fast16_t y); + void _draw_pixel(uint_fast16_t x, uint_fast16_t y, uint32_t value); + void _update_transferred_rect(uint_fast16_t &xs, uint_fast16_t &ys, uint_fast16_t &xe, uint_fast16_t &ye); + }; + +//---------------------------------------------------------------------------- + } +} diff --git a/src/lgfx/v1/platforms/esp32/common.cpp b/src/lgfx/v1/platforms/esp32/common.cpp index db705a77..3a8493c4 100644 --- a/src/lgfx/v1/platforms/esp32/common.cpp +++ b/src/lgfx/v1/platforms/esp32/common.cpp @@ -1446,7 +1446,7 @@ namespace lgfx break; } - len = length < 33 ? length : 33; + len = length < 32 ? length : 32; if (length == len && last_nack && len > 1) { --len; } length -= len;