18#ifndef ENABLE_GxEPD2_GFX
20#define ENABLE_GxEPD2_GFX 0
25#define GxEPD2_GFX_BASE_CLASS GxEPD2_GFX
27#define GxEPD2_GFX_BASE_CLASS GFX
29#include <Adafruit_GFX.h>
30#define GxEPD2_GFX_BASE_CLASS Adafruit_GFX
81template<
typename GxEPD2_Type, const u
int16_t page_height>
87 GxEPD2_BW(GxEPD2_Type epd2_instance) : GxEPD2_GFX_BASE_CLASS(
epd2, GxEPD2_Type::WIDTH, GxEPD2_Type::HEIGHT),
epd2(epd2_instance)
89 GxEPD2_BW(GxEPD2_Type epd2_instance) : GxEPD2_GFX_BASE_CLASS(GxEPD2_Type::WIDTH, GxEPD2_Type::HEIGHT),
epd2(epd2_instance)
92 _page_height = page_height;
93 _pages = (HEIGHT / _page_height) + ((HEIGHT % _page_height) > 0);
96 _using_partial_mode =
false;
119 if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
return;
120 if (_mirror) x = width() - x - 1;
122 switch (getRotation())
141 if ((x < 0) || (x >= int16_t(_pw_w)) || (y < 0) || (y >= int16_t(_pw_h)))
return;
143 y -= _current_page * _page_height;
144 if (_reverse) y = _page_height - y - 1;
146 if ((y < 0) || (y >= int16_t(_page_height)))
return;
147 uint16_t i = x / 4 + y * (_pw_w / 4);
148 _buffer[i] = (_buffer[i] & (0xFF ^ (3 << 2 * (3 - x % 4))));
154 uint32_t brightness = (uint32_t(color & 0xF800) + uint32_t((color & 0x07E0) << 5) + uint32_t((color & 0x001F) << 11));
155 brb = uint8_t((brightness - 1) / 0xC000ul);
157 _buffer[i] = (_buffer[i] | (brb << 2 * (3 - x % 4)));
163 if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
return;
164 if (_mirror) x = width() - x - 1;
166 switch (getRotation())
185 if ((x < 0) || (x >= _pw_w) || (y < 0) || (y >= _pw_h))
return;
187 y -= _current_page * _page_height;
189 if ((y < 0) || (y >= _page_height))
return;
190 uint16_t i = x / 4 + y * (_pw_w / 4);
191 _buffer[i] = (_buffer[i] & (0xFF ^ (3 << 2 * (3 - x % 4))));
192 _buffer[i] = (_buffer[i] | ((grey >> 6) << 2 * (3 - x % 4)));
195 void init(uint32_t serial_diag_bitrate = 0)
197 epd2.init(serial_diag_bitrate);
198 _using_partial_mode =
false;
209 void init(uint32_t serial_diag_bitrate,
bool initial, uint16_t reset_duration = 10,
bool pulldown_rst_mode =
false)
211 epd2.init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode);
212 _using_partial_mode =
false;
220 void init(uint32_t serial_diag_bitrate,
bool initial, uint16_t reset_duration,
bool pulldown_rst_mode, SPIClass& spi, SPISettings spi_settings)
222 epd2.selectSPI(spi, spi_settings);
223 epd2.init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode);
224 _using_partial_mode =
false;
231 uint32_t brightness = (uint32_t(color & 0xF800) + uint32_t((color & 0x07E0) << 5) + uint32_t((color & 0x001F) << 11));
232 uint8_t brb = uint8_t((brightness - 1) / 0xC000ul);
233 uint8_t data = brb * 0b01010101;
234 for (uint16_t x = 0; x <
sizeof(_buffer); x++)
241 void display(
bool partial_update_mode =
false)
243 if (partial_update_mode)
epd2.writeImage(_buffer, 0, 0, WIDTH, _page_height);
244 else epd2.writeImageForFullRefresh(_buffer, 0, 0, WIDTH, _page_height);
245 epd2.refresh(partial_update_mode);
246 if (
epd2.hasFastPartialUpdate)
248 epd2.writeImageAgain(_buffer, 0, 0, WIDTH, _page_height);
250 if (!partial_update_mode)
epd2.powerOff();
261 x = gx_uint16_min(x, width());
262 y = gx_uint16_min(y, height());
263 w = gx_uint16_min(w, width() - x);
264 h = gx_uint16_min(h, height() - y);
266 uint16_t y_part = _reverse ? HEIGHT - h - y : y;
267 epd2.writeImagePart(_buffer, x, y_part, WIDTH, _page_height, x, y, w, h);
268 epd2.refresh(x, y, w, h);
269 if (
epd2.hasFastPartialUpdate)
271 epd2.writeImagePartAgain(_buffer, x, y_part, WIDTH, _page_height, x, y, w, h);
277 _using_partial_mode =
false;
291 _pw_x = gx_uint16_min(x, width());
292 _pw_y = gx_uint16_min(y, height());
293 _pw_w = gx_uint16_min(w, width() - _pw_x);
294 _pw_h = gx_uint16_min(h, height() - _pw_y);
295 _rotate(_pw_x, _pw_y, _pw_w, _pw_h);
296 _using_partial_mode =
true;
299 if (_pw_w % 8 > 0) _pw_w += 8 - _pw_w % 8;
307 _second_phase =
false;
314 if (_using_partial_mode)
316 uint32_t offset = _reverse ? (HEIGHT - _pw_h) * _pw_w / 8 : 0;
317 epd2.writeImage(_buffer + offset, _pw_x, _pw_y, _pw_w, _pw_h);
318 epd2.refresh(_pw_x, _pw_y, _pw_w, _pw_h);
319 if (
epd2.hasFastPartialUpdate)
321 epd2.writeImageAgain(_buffer + offset, _pw_x, _pw_y, _pw_w, _pw_h);
327 epd2.writeImageForFullRefresh(_buffer, 0, 0, WIDTH, HEIGHT);
329 if (
epd2.hasFastPartialUpdate)
331 epd2.writeImageAgain(_buffer, 0, 0, WIDTH, HEIGHT);
338 uint16_t page_ys = _current_page * _page_height;
339 if (_using_partial_mode)
343 uint16_t page_ye = _current_page < int16_t(_pages - 1) ? page_ys + _page_height : HEIGHT;
344 uint16_t dest_ys = _pw_y + page_ys;
345 uint16_t dest_ye = gx_uint16_min(_pw_y + _pw_h, _pw_y + page_ye);
346 if (dest_ye > dest_ys)
350 uint32_t offset = _reverse ? (_page_height - (dest_ye - dest_ys)) * _pw_w / 8 : 0;
351 if (!_second_phase)
epd2.writeImage(_buffer + offset, _pw_x, dest_ys, _pw_w, dest_ye - dest_ys);
352 else epd2.writeImageAgain(_buffer + offset, _pw_x, dest_ys, _pw_w, dest_ye - dest_ys);
361 if (_current_page == int16_t(_pages))
366 epd2.refresh(_pw_x, _pw_y, _pw_w, _pw_h);
367 if (
epd2.hasFastPartialUpdate)
369 _second_phase =
true;
381 if (!_second_phase)
epd2.writeImageForFullRefresh(_buffer, 0, page_ys, WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys));
382 else epd2.writeImageAgain(_buffer, 0, page_ys, WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys));
384 if (_current_page == int16_t(_pages))
387 if (
epd2.hasFastPartialUpdate)
392 _second_phase =
true;
397 }
else epd2.refresh(
false);
407 void drawPaged(
void (*drawCallback)(
const void*),
const void* pv)
413 if (_using_partial_mode)
415 uint32_t offset = _reverse ? (HEIGHT - _pw_h) * _pw_w / 8 : 0;
416 epd2.writeImage(_buffer + offset, _pw_x, _pw_y, _pw_w, _pw_h);
417 epd2.refresh(_pw_x, _pw_y, _pw_w, _pw_h);
418 if (
epd2.hasFastPartialUpdate)
420 epd2.writeImageAgain(_buffer + offset, _pw_x, _pw_y, _pw_w, _pw_h);
426 epd2.writeImageForFullRefresh(_buffer, 0, 0, WIDTH, HEIGHT);
428 if (
epd2.hasFastPartialUpdate)
430 epd2.writeImageAgain(_buffer, 0, 0, WIDTH, HEIGHT);
437 if (_using_partial_mode)
439 for (uint16_t phase = 1; phase <= 2; phase++)
441 for (_current_page = 0; _current_page < _pages; _current_page++)
443 uint16_t page_ys = _current_page * _page_height;
444 uint16_t page_ye = _current_page < (_pages - 1) ? page_ys + _page_height : HEIGHT;
445 uint16_t dest_ys = _pw_y + page_ys;
446 uint16_t dest_ye = gx_uint16_min(_pw_y + _pw_h, _pw_y + page_ye);
447 if (dest_ye > dest_ys)
451 uint32_t offset = _reverse ? (_page_height - (dest_ye - dest_ys)) * _pw_w / 8 : 0;
452 if (phase == 1)
epd2.writeImage(_buffer + offset, _pw_x, dest_ys, _pw_w, dest_ye - dest_ys);
453 else epd2.writeImageAgain(_buffer + offset, _pw_x, dest_ys, _pw_w, dest_ye - dest_ys);
456 epd2.refresh(_pw_x, _pw_y, _pw_w, _pw_h);
457 if (!
epd2.hasFastPartialUpdate)
break;
463 for (_current_page = 0; _current_page < _pages; _current_page++)
465 uint16_t page_ys = _current_page * _page_height;
468 epd2.writeImageForFullRefresh(_buffer, 0, page_ys, WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys));
471 if (
epd2.hasFastPartialUpdate)
474 for (_current_page = 0; _current_page < _pages; _current_page++)
476 uint16_t page_ys = _current_page * _page_height;
479 epd2.writeImageAgain(_buffer, 0, page_ys, WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys));
488 void drawInvertedBitmap(int16_t x, int16_t y,
const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color)
491 int16_t byteWidth = (w + 7) / 8;
493 for (int16_t j = 0; j < h; j++)
495 for (int16_t i = 0; i < w; i++ )
497 if (i & 7)
byte <<= 1;
500#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
501 byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
503 byte = bitmap[j * byteWidth + i / 8];
514 void drawGreyPixmap(
const uint8_t pixmap[], int16_t depth, int16_t x, int16_t y, int16_t w, int16_t h)
520 int16_t byteWidth = (w + 7) / 8;
522 for (int16_t j = 0; j < h; j++)
524 for (int16_t i = 0; i < w; i++ )
526 if (i & 7)
byte <<= 1;
529#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
530 byte = pgm_read_byte(&pixmap[j * byteWidth + i / 8]);
532 byte = pixmap[j * byteWidth + i / 8];
535 uint16_t color =
byte & 0x80 ? 0xFFFF : 0x0000;
543 int16_t byteWidth = (w + 3) / 4;
545 for (int16_t j = 0; j < h; j++)
547 for (int16_t i = 0; i < w; i++ )
549 if (i & 3)
byte <<= 2;
552#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
553 byte = pgm_read_byte(&pixmap[j * byteWidth + i / 4]);
555 byte = pixmap[j * byteWidth + i / 4];
565 int16_t byteWidth = (w + 1) / 2;
567 for (int16_t j = 0; j < h; j++)
569 for (int16_t i = 0; i < w; i++ )
571 if (i & 1)
byte <<= 4;
574#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
575 byte = pgm_read_byte(&pixmap[j * byteWidth + i / 2]);
577 byte = pixmap[j * byteWidth + i / 2];
580 uint8_t grey =
byte & 0xF0;
581 if ((grey < 0xF0) && (grey >= 0xA0)) grey = 0x80;
582 else if ((grey < 0xF0) && (grey > 0x00)) grey = 0x40;
591 for (int16_t j = 0; j < h; j++)
593 for (int16_t i = 0; i < w; i++ )
595#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
596 byte = pgm_read_byte(&pixmap[j * w + i]);
598 byte = pixmap[j * w + i];
611 epd2.clearScreen(value);
615 epd2.writeScreenBuffer(value);
618 void writeImage(
const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h,
bool invert =
false,
bool mirror_y =
false,
bool pgm =
false)
620 epd2.writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
622 void writeImagePart(
const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
623 int16_t x, int16_t y, int16_t w, int16_t h,
bool invert =
false,
bool mirror_y =
false,
bool pgm =
false)
625 epd2.writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
627 void writeImage(
const uint8_t* black,
const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h,
bool invert,
bool mirror_y,
bool pgm)
629 epd2.writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
631 void writeImage(
const uint8_t* black,
const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h)
633 epd2.writeImage(black, color, x, y, w, h,
false,
false,
false);
635 void writeImagePart(
const uint8_t* black,
const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
636 int16_t x, int16_t y, int16_t w, int16_t h,
bool invert,
bool mirror_y,
bool pgm)
638 epd2.writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
640 void writeImagePart(
const uint8_t* black,
const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
641 int16_t x, int16_t y, int16_t w, int16_t h)
643 epd2.writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h,
false,
false,
false);
646 void writeNative(
const uint8_t* data1,
const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h,
bool invert,
bool mirror_y,
bool pgm)
648 epd2.writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
651 void drawImage(
const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h,
bool invert =
false,
bool mirror_y =
false,
bool pgm =
false)
653 epd2.drawImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
655 void drawImagePart(
const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
656 int16_t x, int16_t y, int16_t w, int16_t h,
bool invert =
false,
bool mirror_y =
false,
bool pgm =
false)
658 epd2.drawImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
660 void drawImage(
const uint8_t* black,
const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h,
bool invert,
bool mirror_y,
bool pgm)
662 epd2.drawImage(black, color, x, y, w, h, invert, mirror_y, pgm);
664 void drawImage(
const uint8_t* black,
const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h)
666 epd2.drawImage(black, color, x, y, w, h,
false,
false,
false);
668 void drawImagePart(
const uint8_t* black,
const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
669 int16_t x, int16_t y, int16_t w, int16_t h,
bool invert,
bool mirror_y,
bool pgm)
671 epd2.drawImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
673 void drawImagePart(
const uint8_t* black,
const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
674 int16_t x, int16_t y, int16_t w, int16_t h)
676 epd2.drawImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h,
false,
false,
false);
679 void drawNative(
const uint8_t* data1,
const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h,
bool invert,
bool mirror_y,
bool pgm)
681 epd2.drawNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
683 void refresh(
bool partial_update_mode =
false)
685 epd2.refresh(partial_update_mode);
686 if (!partial_update_mode)
epd2.powerOff();
688 void refresh(int16_t x, int16_t y, int16_t w, int16_t h)
690 epd2.refresh(x, y, w, h);
703 template <
typename T>
static inline void
710 static inline uint16_t gx_uint16_min(uint16_t a, uint16_t b)
712 return (a < b ? a : b);
714 static inline uint16_t gx_uint16_max(uint16_t a, uint16_t b)
716 return (a > b ? a : b);
718 void _rotate(uint16_t& x, uint16_t& y, uint16_t& w, uint16_t& h)
720 switch (getRotation())
739 uint8_t _buffer[(GxEPD2_Type::WIDTH / (8/
GxEPD_BPP)) * page_height];
740 bool _using_partial_mode, _second_phase, _mirror, _reverse;
741 uint16_t _width_bytes, _pixel_bytes;
742 int16_t _current_page;
743 uint16_t _pages, _page_height;
744 uint16_t _pw_x, _pw_y, _pw_w, _pw_h;
void writeImagePart(const uint8_t *black, const uint8_t *color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y, int16_t w, int16_t h)
void refresh(int16_t x, int16_t y, int16_t w, int16_t h)
void init(uint32_t serial_diag_bitrate=0)
void drawNative(const uint8_t *data1, const uint8_t *data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
void writeImagePart(const uint8_t *black, const uint8_t *color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
void writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
GxEPD2_BW(GxEPD2_Type epd2_instance)
void fillScreen(uint16_t color)
void clearScreen(uint8_t value=0xFF)
void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode, SPIClass &spi, SPISettings spi_settings)
void drawGreyPixmap(const uint8_t pixmap[], int16_t depth, int16_t x, int16_t y, int16_t w, int16_t h)
void drawPaged(void(*drawCallback)(const void *), const void *pv)
void display(bool partial_update_mode=false)
void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration=10, bool pulldown_rst_mode=false)
void displayWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
void drawImage(const uint8_t *black, const uint8_t *color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
void writeImage(const uint8_t *black, const uint8_t *color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
void drawImagePart(const uint8_t *black, const uint8_t *color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y, int16_t w, int16_t h)
void drawImage(const uint8_t *black, const uint8_t *color, int16_t x, int16_t y, int16_t w, int16_t h)
void drawInvertedBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color)
void drawPixel(int16_t x, int16_t y, uint16_t color)
void writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
void writeImage(const uint8_t *black, const uint8_t *color, int16_t x, int16_t y, int16_t w, int16_t h)
void writeScreenBuffer(uint8_t value=0xFF)
void refresh(bool partial_update_mode=false)
void drawGreyPixel(int16_t x, int16_t y, uint8_t grey)
void drawImagePart(const uint8_t *black, const uint8_t *color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
void drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
void writeNative(const uint8_t *data1, const uint8_t *data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
void drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
void setPartialWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h)