From 29ca2268fef8a3477b93e2ee7f293aeccba8fcda Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Wed, 23 Mar 2022 21:25:27 +0100 Subject: [PATCH] [P096] Add support for Waveshare 2in7 264x176 pixel monochrome ePaper display --- lib/LOLIN_EPD/src/LOLIN_EPD.cpp | 4 +- lib/LOLIN_EPD/src/LOLIN_EPD.h | 5 +- lib/LOLIN_EPD/src/Waveshare_2in7.cpp | 528 +++++++++++++++++++++ lib/LOLIN_EPD/src/Waveshare_2in7.h | 116 +++++ src/_P096_eInk.ino | 312 +----------- src/src/PluginStructs/P096_data_struct.cpp | 18 + src/src/PluginStructs/P096_data_struct.h | 36 +- 7 files changed, 713 insertions(+), 306 deletions(-) create mode 100644 lib/LOLIN_EPD/src/Waveshare_2in7.cpp create mode 100644 lib/LOLIN_EPD/src/Waveshare_2in7.h diff --git a/lib/LOLIN_EPD/src/LOLIN_EPD.cpp b/lib/LOLIN_EPD/src/LOLIN_EPD.cpp index 76586d297..ce160c911 100644 --- a/lib/LOLIN_EPD/src/LOLIN_EPD.cpp +++ b/lib/LOLIN_EPD/src/LOLIN_EPD.cpp @@ -48,7 +48,9 @@ LOLIN_EPD::~LOLIN_EPD() { free(bw_buf); - free(red_buf); + if (red_buf) { + free(red_buf); + } } /**************************************************************************/ diff --git a/lib/LOLIN_EPD/src/LOLIN_EPD.h b/lib/LOLIN_EPD/src/LOLIN_EPD.h index 4fd2d9b8e..dacd00071 100644 --- a/lib/LOLIN_EPD/src/LOLIN_EPD.h +++ b/lib/LOLIN_EPD/src/LOLIN_EPD.h @@ -87,8 +87,8 @@ protected: red_bufsize; ///< size of the red buffer bool singleByteTxns; ///< if true CS will go high after every data byte transferred - uint8_t *bw_buf; ///< the pointer to the black and white buffer if using on-chip ram - uint8_t *red_buf; ///< the pointer to the red buffer if using on-chip ram + uint8_t *bw_buf = nullptr; ///< the pointer to the black and white buffer if using on-chip ram + uint8_t *red_buf = nullptr; ///< the pointer to the red buffer if using on-chip ram void sendCmd(uint8_t c); void sendData(uint8_t data); @@ -116,5 +116,6 @@ private: #include "LOLIN_IL3897.h" #include "LOLIN_UC8151D.h" #include "LOLIN_SSD1680.h" +#include "Waveshare_2in7.h" #endif diff --git a/lib/LOLIN_EPD/src/Waveshare_2in7.cpp b/lib/LOLIN_EPD/src/Waveshare_2in7.cpp new file mode 100644 index 000000000..d3135a83c --- /dev/null +++ b/lib/LOLIN_EPD/src/Waveshare_2in7.cpp @@ -0,0 +1,528 @@ +#include "LOLIN_EPD.h" +#include "Waveshare_2in7.h" + +#define ALLSCREEN_GRAGHBYTES 4000 + +/////////////////////////////////////////////////// + + +/////////////////EPD settings Functions///////////////////// + +/////////////////////////////////////LUT////////////////////////////////////////////// +static const unsigned char EPD_2in7_gray_lut_vcom[] = { + 0x00, 0x00, + 0x00, 0x0A,0x00, 0x00, 0x00, 0x01, + 0x60, 0x14,0x14, 0x00, 0x00, 0x01, + 0x00, 0x14,0x00, 0x00, 0x00, 0x01, + 0x00, 0x13,0x0A, 0x01, 0x00, 0x01, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, +}; + +// R21 +static const unsigned char EPD_2in7_gray_lut_ww[] = { + 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x10, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0xA0, 0x13, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// R22H r +static const unsigned char EPD_2in7_gray_lut_bw[] = { + 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0x99, 0x0C, 0x01, 0x03, 0x04, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// R23H w +static const unsigned char EPD_2in7_gray_lut_wb[] = { + 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0x99, 0x0B, 0x04, 0x04, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// R24H b +static const unsigned char EPD_2in7_gray_lut_bb[] = { + 0x80, 0x0A, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x20, 0x14, 0x0A, 0x00, 0x00, 0x01, + 0x50, 0x13, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#define BUSY_WAIT 1000 + +/*! + @brief constructor if using on-chip RAM and software SPI + @param width the width of the display in pixels + @param height the height of the display in pixels + @param SID the SID pin to use + @param SCLK the SCLK pin to use + @param DC the data/command pin to use + @param RST the reset pin to use + @param CS the chip select pin to use + @param BUSY the busy pin to use + */ + +/**************************************************************************/ +Waveshare_2in7::Waveshare_2in7(int width, int height, int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS, int8_t BUSY) + : LOLIN_EPD(width, height, SID, SCLK, DC, RST, CS, BUSY) { + if ((height % 8) > 0) { + _height_8bit = (height / 8 + 1) * 8; + } else { + _height_8bit = height; + } + + bw_bufsize = width * _height_8bit / 8; + bw_buf = (uint8_t *)malloc(bw_bufsize); + + // red_buf = (uint8_t *)malloc(width * _height_8bit / 8); // + // red_bufsize = bw_bufsize; +} + +Waveshare_2in7::Waveshare_2in7(int width, int height, int8_t DC, int8_t RST, int8_t CS, int8_t BUSY) + : LOLIN_EPD(width, height, DC, RST, CS, BUSY) { + if ((height % 8) > 0) { + _height_8bit = (height / 8 + 1) * 8; + } else { + _height_8bit = height; + } + + bw_bufsize = width * _height_8bit / 8; + bw_buf = (uint8_t *)malloc(bw_bufsize); + + // red_buf = (uint8_t *)malloc(width * _height_8bit / 8); + // red_bufsize = bw_bufsize; +} + +/**************************************************************************/ + +/*! + @brief begin communication with and set up the display. + @param reset if true the reset pin will be toggled. + */ + +/**************************************************************************/ +void Waveshare_2in7::begin(bool reset) { + LOLIN_EPD::begin(reset); + + readBusy(); + sendCmd(0x12); + readBusy(); + + sendCmd(POWER_SETTING); + sendData(0x03); // VDS_EN, VDG_EN + sendData(0x00); // VCOM_HV, VGHL_LV[1], VGHL_LV[0] + sendData(0x2b); // VDH + sendData(0x2b); // VDL + sendData(0x09); // VDHR + sendCmd(BOOSTER_SOFT_START); + sendData(0x07); + sendData(0x07); + sendData(0x17); + + // Power optimization + sendCmd(POWER_OPTIMIZATION); + sendData(0x60); + sendData(0xA5); + + // Power optimization + sendCmd(POWER_OPTIMIZATION); + sendData(0x89); + sendData(0xA5); + + // Power optimization + sendCmd(POWER_OPTIMIZATION); + sendData(0x90); + sendData(0x00); + + // Power optimization + sendCmd(POWER_OPTIMIZATION); + sendData(0x93); + sendData(0x2A); + + // Power optimization + sendCmd(POWER_OPTIMIZATION); + sendData(0xA0); + sendData(0xA5); + + // Power optimization + sendCmd(POWER_OPTIMIZATION); + sendData(0xA1); + sendData(0x00); + + // Power optimization + sendCmd(POWER_OPTIMIZATION); + sendData(0x73); + sendData(0x41); + + sendCmd(PARTIAL_DISPLAY_REFRESH); + sendData(0x00); + sendCmd(WS2IN7_POWER_ON); + readBusy(); + + sendCmd(PANEL_SETTING); + sendData(0xAF); // KW-BF KWR-AF BWROTP 0f + sendCmd(PLL_CONTROL); + sendData(0x3A); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ + sendCmd(VCM_DC_SETTING_REGISTER); + sendData(0x12); + delay(2); + setLut(); + + /* EPD hardware init end */ + readBusy(); +} + +/** + * @brief: set the look-up tables + */ +void Waveshare_2in7::setLut(void) { + unsigned int count; + + sendCmd(LUT_FOR_VCOM); // vcom + + for (count = 0; count < 44; count++) { + sendData(lut_vcom_dc[count]); + } + + sendCmd(LUT_WHITE_TO_WHITE); // ww -- + + for (count = 0; count < 42; count++) { + sendData(lut_ww[count]); + } + + sendCmd(LUT_BLACK_TO_WHITE); // bw r + + for (count = 0; count < 42; count++) { + sendData(lut_bw[count]); + } + + sendCmd(LUT_WHITE_TO_BLACK); // wb w + + for (count = 0; count < 42; count++) { + sendData(lut_bb[count]); + } + + sendCmd(LUT_BLACK_TO_BLACK); // bb b + + for (count = 0; count < 42; count++) { + sendData(lut_wb[count]); + } +} + +void Waveshare_2in7::display() { + // sendCmd(DATA_START_TRANSMISSION_1); // ?? write RAM for black(0)/white (1) + // delay(2); + + // for (uint16_t i = 0; i < bw_bufsize; i++) { + // sendData(0xFF); + // } + // delay(2); + + sendCmd(DATA_START_TRANSMISSION_2); // write RAM for black(0)/white (1) + delay(2); + + for (uint16_t i = 0; i < bw_bufsize; i++) { + sendData(bw_buf[i]); + } + delay(2); + + update(); +} + +void Waveshare_2in7::update() { + sendCmd(DISPLAY_REFRESH); + delay(200); + readBusy(); +} + +/**************************************************************************/ + +/*! + @brief draw a single pixel on the screen + @param x the x axis position + @param y the y axis position + @param color the color of the pixel + */ + +/**************************************************************************/ +void Waveshare_2in7::drawPixel(int16_t x, int16_t y, uint16_t color) { + uint8_t *pBuf; + + // check rotation, move pixel around if necessary + switch (getRotation()) { + case 1: + EPD_swap(x, y); + x = WIDTH - x - 1; + break; + case 2: + x = WIDTH - x - 1; + y = HEIGHT - y - 1; + break; + case 3: + EPD_swap(x, y); + y = HEIGHT - y - 1; + break; + } + + // Transformed to native pixels + if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) { + return; + } + + // make our buffer happy + x = (x == 0 ? 1 : x); + + // uint16_t addr = (x * height() + y) / 8; + uint16_t addr = (x + _height_8bit * y) / 8; + + // if (color == EPD_RED) { + // pBuf = red_buf + addr; + // } else { + pBuf = bw_buf + addr; + + // } + + // x is which column + switch (color) { + case EPD_WHITE: + *pBuf |= (0x80 >> (x % 8)); // (1 << (7 - y % 8)); + break; + case EPD_RED: + case EPD_BLACK: + *pBuf &= ~(0x80 >> (x % 8)); // ~(1 << (7 - y % 8)); + break; + + // case EPD_INVERSE: + // *pBuf ^= (0x80 >> (x % 8)); // (1 << (7 - y % 8)); + // break; + } +} + +/**************************************************************************/ + +/*! + @brief clear all data buffers + */ + +/**************************************************************************/ +void Waveshare_2in7::clearBuffer() { + memset(bw_buf, 0xFF, bw_bufsize); +} + +/**************************************************************************/ + +/*! + @brief clear the display twice to remove any spooky ghost images + */ + +/**************************************************************************/ +void Waveshare_2in7::clearDisplay() { + clearBuffer(); + display(); + delay(100); + display(); +} + +void Waveshare_2in7::readBusy() { + if (busy >= 0) { + while (1) { + if (digitalRead(busy) == 0) { + delay(1); + break; + } + delay(0); + } + } else { + delay(BUSY_WAIT); + } +} + +void Waveshare_2in7::selectLUT(uint8_t *wave_data) { + uint8_t count; + + sendCmd(0x32); + + for (count = 0; count < 70; count++) { + sendData(pgm_read_byte(&wave_data[count])); + } +} + +void Waveshare_2in7::deepSleep() { + sendCmd(DEEP_SLEEP); + sendData(0xa5); +} + +void Waveshare_2in7::partInit() +{ + // partBaseImg(); + + // sendCmd(0x2C); //VCOM Voltage + // sendData(0x26); + + // readBusy(); + // selectLUT((unsigned char *)LUT_DATA_part); + // sendCmd(0x37); + // sendData(0x00); + // sendData(0x00); + // sendData(0x00); + // sendData(0x00); + // sendData(0x40); + // sendData(0x00); + // sendData(0x00); + + // sendCmd(0x22); + // sendData(0xC0); + // sendCmd(0x20); + // readBusy(); + + // sendCmd(0x3C); //BorderWavefrom + // sendData(0x01); +} + +void Waveshare_2in7::partBaseImg() +{ + sendCmd(0x24); ////Write Black and White image to RAM + + for (uint16_t i = 0; i < bw_bufsize; i++) { + sendData(bw_buf[i]); + } + + sendCmd(0x26); ////Write Black and White image to RAM + + for (uint16_t i = 0; i < bw_bufsize; i++) { + sendData(bw_buf[i]); + } + + update(); +} + +void Waveshare_2in7::partUpdate() +{ + sendCmd(0x22); + sendData(0x0C); + sendCmd(0x20); + readBusy(); +} + +void Waveshare_2in7::partDisplay(int16_t x_start, int16_t y_start, const unsigned char *datas, int16_t PART_COLUMN, int16_t PART_LINE) +{ + int16_t i; + int16_t x_end, y_start1, y_start2, y_end1, y_end2; + + x_start = x_start / 8; // + x_end = x_start + PART_LINE / 8 - 1; + + y_start1 = 0; + y_start2 = y_start; + + if (y_start >= 256) + { + y_start1 = y_start2 / 256; + y_start2 = y_start2 % 256; + } + y_end1 = 0; + y_end2 = y_start + PART_COLUMN - 1; + + if (y_end2 >= 256) + { + y_end1 = y_end2 / 256; + y_end2 = y_end2 % 256; + } + + sendCmd(0x44); // set RAM x address start/end, in page 35 + sendData(x_start); // RAM x address start at 00h; + sendData(x_end); // RAM x address end at 0fh(15+1)*8->128 + sendCmd(0x45); // set RAM y address start/end, in page 35 + sendData(y_start2); // RAM y address start at 0127h; + sendData(y_start1); // RAM y address start at 0127h; + sendData(y_end2); // RAM y address end at 00h; + sendData(y_end1); // ????=0 + + sendCmd(0x4E); // set RAM x address count to 0; + sendData(x_start); + sendCmd(0x4F); // set RAM y address count to 0X127; + sendData(y_start2); + sendData(y_start1); + + sendCmd(0x24); // Write Black and White image to RAM + + for (i = 0; i < PART_COLUMN * PART_LINE / 8; i++) + { + sendData(pgm_read_byte(&datas[i])); + } + partUpdate(); +} + +const unsigned char lut_vcom_dc[] = { + 0x00, 0x00, + 0x00, 0x0F,0x0F, 0x00, 0x00, 0x05, + 0x00, 0x32,0x32, 0x00, 0x00, 0x02, + 0x00, 0x0F,0x0F, 0x00, 0x00, 0x05, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, + 0x00, 0x00,0x00, 0x00, 0x00, 0x00, +}; + +// R21H +const unsigned char lut_ww[] = { + 0x50, 0x0F, 0x0F, 0x00, 0x00, 0x05, + 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, + 0xA0, 0x0F, 0x0F, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// R22H r +const unsigned char lut_bw[] = +{ + 0x50, 0x0F, 0x0F, 0x00, 0x00, 0x05, + 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, + 0xA0, 0x0F, 0x0F, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// R24H b +const unsigned char lut_bb[] = +{ + 0xA0, 0x0F, 0x0F, 0x00, 0x00, 0x05, + 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, + 0x50, 0x0F, 0x0F, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// R23H w +const unsigned char lut_wb[] = +{ + 0xA0, 0x0F, 0x0F, 0x00, 0x00, 0x05, + 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, + 0x50, 0x0F, 0x0F, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/lib/LOLIN_EPD/src/Waveshare_2in7.h b/lib/LOLIN_EPD/src/Waveshare_2in7.h new file mode 100644 index 000000000..e9573fb48 --- /dev/null +++ b/lib/LOLIN_EPD/src/Waveshare_2in7.h @@ -0,0 +1,116 @@ +#ifndef __Waveshare_2in7_H +#define __Waveshare_2in7_H + +#ifdef __AVR__ + # include +#elif defined(ESP8266) || defined(ESP32) + # include +#else // ifdef __AVR__ + # define pgm_read_byte(addr) (*(const unsigned char *)(addr)) ///< read bytes from program memory +#endif // ifdef __AVR__ + +#include "LOLIN_EPD.h" + +// EPD2IN7 commands +#define PANEL_SETTING 0x00 +#define POWER_SETTING 0x01 +#define WS2IN7_POWER_OFF 0x02 +#define POWER_OFF_SEQUENCE_SETTING 0x03 +#define WS2IN7_POWER_ON 0x04 +#define POWER_ON_MEASURE 0x05 +#define BOOSTER_SOFT_START 0x06 +#define DEEP_SLEEP 0x07 +#define DATA_START_TRANSMISSION_1 0x10 +#define DATA_STOP 0x11 +#define DISPLAY_REFRESH 0x12 +#define DATA_START_TRANSMISSION_2 0x13 +#define PARTIAL_DATA_START_TRANSMISSION_1 0x14 +#define PARTIAL_DATA_START_TRANSMISSION_2 0x15 +#define PARTIAL_DISPLAY_REFRESH 0x16 +#define LUT_FOR_VCOM 0x20 +#define LUT_WHITE_TO_WHITE 0x21 +#define LUT_BLACK_TO_WHITE 0x22 +#define LUT_WHITE_TO_BLACK 0x23 +#define LUT_BLACK_TO_BLACK 0x24 +#define PLL_CONTROL 0x30 +#define TEMPERATURE_SENSOR_COMMAND 0x40 +#define TEMPERATURE_SENSOR_CALIBRATION 0x41 +#define TEMPERATURE_SENSOR_WRITE 0x42 +#define TEMPERATURE_SENSOR_READ 0x43 +#define VCOM_AND_DATA_INTERVAL_SETTING 0x50 +#define LOW_POWER_DETECTION 0x51 +#define TCON_SETTING 0x60 +#define TCON_RESOLUTION 0x61 +#define SOURCE_AND_GATE_START_SETTING 0x62 +#define GET_STATUS 0x71 +#define AUTO_MEASURE_VCOM 0x80 +#define VCOM_VALUE 0x81 +#define VCM_DC_SETTING_REGISTER 0x82 +#define PROGRAM_MODE 0xA0 +#define ACTIVE_PROGRAM 0xA1 +#define READ_OTP_DATA 0xA2 +#define POWER_OPTIMIZATION 0xF8 + +extern const unsigned char lut_vcom_dc[]; +extern const unsigned char lut_ww[]; +extern const unsigned char lut_bw[]; +extern const unsigned char lut_bb[]; +extern const unsigned char lut_wb[]; + +/**************************************************************************/ + +/*! + @brief Class for interfacing with IL3897 EPD drivers + */ + +/**************************************************************************/ +class Waveshare_2in7 : public LOLIN_EPD { +public: + + Waveshare_2in7(int width, + int height, + int8_t SID, + int8_t SCLK, + int8_t DC, + int8_t RST, + int8_t CS, + int8_t BUSY = -1); + Waveshare_2in7(int width, + int height, + int8_t DC, + int8_t RST, + int8_t CS, + int8_t BUSY = -1); + + void begin(bool reset = true); + + void drawPixel(int16_t x, + int16_t y, + uint16_t color); + + void display(); + void update(); + + void clearBuffer(); + void clearDisplay(); + + void deepSleep(); + + void partBaseImg(); + void partInit(); + void partDisplay(int16_t x_start, + int16_t y_start, + const unsigned char *datas, + int16_t PART_COLUMN, + int16_t PART_LINE); + void partUpdate(); + +protected: + + void readBusy(); + void selectLUT(uint8_t *wave_data); + void setLut(); + int _height_8bit; // height 8-bit alignment +}; + +#endif // ifndef __Waveshare_2in7_H diff --git a/src/_P096_eInk.ino b/src/_P096_eInk.ino index 8041f5302..f1a98e051 100644 --- a/src/_P096_eInk.ino +++ b/src/_P096_eInk.ino @@ -268,11 +268,19 @@ boolean Plugin_096(uint8_t function, struct EventStruct *event, String& string) const __FlashStringHelper *options4[] = { EPD_type_toString(EPD_type_e::EPD_IL3897), EPD_type_toString(EPD_type_e::EPD_UC8151D), - EPD_type_toString(EPD_type_e::EPD_SSD1680) }; + EPD_type_toString(EPD_type_e::EPD_SSD1680), + # if P096_USE_WAVESHARE_2IN7 + EPD_type_toString(EPD_type_e::EPD_WS2IN7) + # endif // if P096_USE_WAVESHARE_2IN7 + }; const int optionValues4[] = { static_cast(EPD_type_e::EPD_IL3897), static_cast(EPD_type_e::EPD_UC8151D), - static_cast(EPD_type_e::EPD_SSD1680) }; + static_cast(EPD_type_e::EPD_SSD1680), + # if P096_USE_WAVESHARE_2IN7 + static_cast(EPD_type_e::EPD_WS2IN7) + # endif // if P096_USE_WAVESHARE_2IN7 + }; addFormSelector(F("eInk display model"), F("p096_type"), static_cast(EPD_type_e::EPD_MAX), @@ -355,7 +363,10 @@ boolean Plugin_096(uint8_t function, struct EventStruct *event, String& string) P096_CommandTrigger_toString(P096_CommandTrigger::ePaper), P096_CommandTrigger_toString(P096_CommandTrigger::il3897), P096_CommandTrigger_toString(P096_CommandTrigger::uc8151d), - P096_CommandTrigger_toString(P096_CommandTrigger::ssd1680) + P096_CommandTrigger_toString(P096_CommandTrigger::ssd1680), + # if P096_USE_WAVESHARE_2IN7 + P096_CommandTrigger_toString(P096_CommandTrigger::ws2in7) + # endif // if P096_USE_WAVESHARE_2IN7 }; const int commandTriggerOptions[] = { static_cast(P096_CommandTrigger::epd), @@ -363,7 +374,10 @@ boolean Plugin_096(uint8_t function, struct EventStruct *event, String& string) static_cast(P096_CommandTrigger::ePaper), static_cast(P096_CommandTrigger::il3897), static_cast(P096_CommandTrigger::uc8151d), - static_cast(P096_CommandTrigger::ssd1680) + static_cast(P096_CommandTrigger::ssd1680), + # if P096_USE_WAVESHARE_2IN7 + static_cast(P096_CommandTrigger::ws2in7) + # endif // if P096_USE_WAVESHARE_2IN7 }; addFormSelector(F("Write Command trigger"), F("p096_commandtrigger"), @@ -556,296 +570,14 @@ boolean Plugin_096(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_WRITE: { -# ifndef BUILD_NO_DEBUG - String tmpString = String(string); -# endif // ifndef BUILD_NO_DEBUG - String arguments = String(string); + P096_data_struct *P096_data = static_cast(getPluginTaskData(event->TaskIndex)); - String command; - String subcommand; - - int argIndex = arguments.indexOf(','); - - if (argIndex) - { - command = arguments.substring(0, argIndex); - arguments = arguments.substring(argIndex + 1); - argIndex = arguments.indexOf(','); - subcommand = arguments.substring(0, argIndex); - success = true; - -# ifndef BUILD_NO_DEBUG - tmpString += "
command= " + command; - tmpString += "
arguments= " + arguments; - tmpString += "
argIndex= " + String(argIndex); - tmpString += "
subcommand= " + subcommand; -# endif // ifndef BUILD_NO_DEBUG - - // if (command.equalsIgnoreCase(F("EPDCMD"))) - // { - // if (subcommand.equalsIgnoreCase(F("CLEAR"))) - // { - // arguments = arguments.substring(argIndex + 1); - // eInkScreen->clearBuffer(); - // eInkScreen->fillScreen(Plugin_096_ParseColor(arguments)); - // eInkScreen->display(); - // eInkScreen->clearBuffer(); - // } - // else if (subcommand.equalsIgnoreCase(F("DEEPSLEEP"))) - // { - // eInkScreen->deepSleep(); - // } - // else if (subcommand.equalsIgnoreCase(F("SEQ_START"))) - // { - // eInkScreen->clearBuffer(); - // eInkScreen->fillScreen(Plugin_096_ParseColor(arguments)); - // plugin_096_sequence_in_progress = true; - // } - // else if (subcommand.equalsIgnoreCase(F("SEQ_END"))) - // { - // # ifndef BUILD_NO_DEBUG - // TimingStats s; - // const unsigned statisticsTimerStart(micros()); - // # endif // ifndef BUILD_NO_DEBUG - // eInkScreen->display(); - - // # ifndef BUILD_NO_DEBUG - // s.add(usecPassedSince(statisticsTimerStart)); - // tmpString += "
Display timings = " + String(s.getAvg()); - // # endif // ifndef BUILD_NO_DEBUG - // eInkScreen->clearBuffer(); - // plugin_096_sequence_in_progress = false; - // } - // else if (subcommand.equalsIgnoreCase(F("INV"))) - // { - // arguments = arguments.substring(argIndex + 1); - // eInkScreen->invertDisplay(arguments.toInt() == 1); - // eInkScreen->display(); - // } - // else if (subcommand.equalsIgnoreCase(F("ROT"))) - // { - // arguments = arguments.substring(argIndex + 1); - // eInkScreen->setRotation(arguments.toInt() % 4); - // eInkScreen->display(); - // } - // else - // { - // success = false; - // } - // } - // else if (command.equalsIgnoreCase(F("EPD"))) - // { - // # ifdef P096_USE_ADA_GRAPHICS - // String tmp = string; - // success = gfxHelper->processCommand(AdaGFXparseTemplate(tmp, PCONFIG(2) / 10)); // Hand it over after replacing - // variables - // # else // ifdef P096_USE_ADA_GRAPHICS - // # ifndef BUILD_NO_DEBUG - // tmpString += "
EPD "; - // # endif // ifndef BUILD_NO_DEBUG - // arguments = arguments.substring(argIndex + 1); - // String sParams[8]; - // int argCount = Plugin_096_StringSplit(arguments, ',', sParams, 8); - - // # ifndef BUILD_NO_DEBUG - - // for (int a = 0; a < argCount && a < 8; a++) - // { - // tmpString += "
ARGS[" + String(a) + "]=" + sParams[a]; - // } - // # endif // ifndef BUILD_NO_DEBUG - - // if (plugin_096_sequence_in_progress == false) - // { - // eInkScreen->clearBuffer(); - // eInkScreen->fillScreen(EPD_WHITE); - // } - - // if (subcommand.equalsIgnoreCase(F("txt"))) - // { - // Plugin_096_FixText(arguments); - // eInkScreen->println(arguments); // write all pending cars - // } - // else if (subcommand.equalsIgnoreCase(F("txz"))) - // { - // eInkScreen->setCursor(sParams[0].toInt(), sParams[1].toInt()); - // Plugin_096_FixText(sParams[2]); - // eInkScreen->println(sParams[2]); // write all pending cars - // } - // else if (subcommand.equalsIgnoreCase(F("txp")) && (argCount == 2)) - // { - // eInkScreen->setCursor(sParams[0].toInt(), sParams[1].toInt()); - // } - // else if (subcommand.equalsIgnoreCase(F("txc")) && ((argCount == 1) || (argCount == 2))) - // { - // if (argCount == 1) { - // eInkScreen->setTextColor(Plugin_096_ParseColor(sParams[0])); - // } - // else { // argCount=2 - // eInkScreen->setTextColor(Plugin_096_ParseColor(sParams[0]), Plugin_096_ParseColor(sParams[1])); - // } - // } - // else if (subcommand.equalsIgnoreCase(F("txs")) && (argCount == 1)) - // { - // eInkScreen->setTextSize(sParams[0].toInt()); - // } - // else if (subcommand.equalsIgnoreCase(F("txtfull")) && (argCount >= 3) && (argCount <= 6)) - // { - // switch (argCount) - // { - // case 3: // single text - // Plugin_096_printText(sParams[2].c_str(), sParams[0].toInt() - 1, sParams[1].toInt() - 1); - // break; - - // case 4: // text + size - // Plugin_096_printText(sParams[3].c_str(), sParams[0].toInt() - 1, sParams[1].toInt() - 1, sParams[2].toInt()); - // break; - - // case 5: // text + size + color - // Plugin_096_printText(sParams[4].c_str(), - // sParams[0].toInt() - 1, - // sParams[1].toInt() - 1, - // sParams[2].toInt(), - // Plugin_096_ParseColor(sParams[3])); - // break; - - // case 6: // text + size + color - // Plugin_096_printText(sParams[5].c_str(), - // sParams[0].toInt() - 1, - // sParams[1].toInt() - 1, - // sParams[2].toInt(), - // Plugin_096_ParseColor(sParams[3]), - // Plugin_096_ParseColor(sParams[4])); - // break; - // default: - // success = false; - // break; - // } - // } - // else if (subcommand.equalsIgnoreCase(F("l")) && (argCount == 5)) - // { - // eInkScreen->drawLine(sParams[0].toInt(), sParams[1].toInt(), sParams[2].toInt(), sParams[3].toInt(), - // Plugin_096_ParseColor(sParams[4])); - // } - // else if (subcommand.equalsIgnoreCase(F("lh")) && (argCount == 3)) - // { - // eInkScreen->drawFastHLine(0, sParams[0].toInt(), sParams[1].toInt(), Plugin_096_ParseColor(sParams[2])); - // } - // else if (subcommand.equalsIgnoreCase(F("lv")) && (argCount == 3)) - // { - // eInkScreen->drawFastVLine(sParams[0].toInt(), 0, sParams[1].toInt(), Plugin_096_ParseColor(sParams[2])); - // } - // else if (subcommand.equalsIgnoreCase(F("r")) && (argCount == 5)) - // { - // eInkScreen->drawRect(sParams[0].toInt(), sParams[1].toInt(), sParams[2].toInt(), sParams[3].toInt(), - // Plugin_096_ParseColor(sParams[4])); - // } - // else if (subcommand.equalsIgnoreCase(F("rf")) && (argCount == 6)) - // { - // eInkScreen->fillRect(sParams[0].toInt(), sParams[1].toInt(), sParams[2].toInt(), sParams[3].toInt(), - // Plugin_096_ParseColor(sParams[5])); - // eInkScreen->drawRect(sParams[0].toInt(), sParams[1].toInt(), sParams[2].toInt(), sParams[3].toInt(), - // Plugin_096_ParseColor(sParams[4])); - // } - // else if (subcommand.equalsIgnoreCase(F("c")) && (argCount == 4)) - // { - // eInkScreen->drawCircle(sParams[0].toInt(), sParams[1].toInt(), sParams[2].toInt(), - // Plugin_096_ParseColor(sParams[3])); - // } - // else if (subcommand.equalsIgnoreCase(F("cf")) && (argCount == 5)) - // { - // eInkScreen->fillCircle(sParams[0].toInt(), sParams[1].toInt(), sParams[2].toInt(), - // Plugin_096_ParseColor(sParams[4])); - // eInkScreen->drawCircle(sParams[0].toInt(), sParams[1].toInt(), sParams[2].toInt(), - // Plugin_096_ParseColor(sParams[3])); - // } - // else if (subcommand.equalsIgnoreCase(F("t")) && (argCount == 7)) - // { - // eInkScreen->drawTriangle(sParams[0].toInt(), - // sParams[1].toInt(), - // sParams[2].toInt(), - // sParams[3].toInt(), - // sParams[4].toInt(), - // sParams[5].toInt(), - // Plugin_096_ParseColor(sParams[6])); - // } - // else if (subcommand.equalsIgnoreCase(F("tf")) && (argCount == 8)) - // { - // eInkScreen->fillTriangle(sParams[0].toInt(), - // sParams[1].toInt(), - // sParams[2].toInt(), - // sParams[3].toInt(), - // sParams[4].toInt(), - // sParams[5].toInt(), - // Plugin_096_ParseColor(sParams[7])); - // eInkScreen->drawTriangle(sParams[0].toInt(), - // sParams[1].toInt(), - // sParams[2].toInt(), - // sParams[3].toInt(), - // sParams[4].toInt(), - // sParams[5].toInt(), - // Plugin_096_ParseColor(sParams[6])); - // } - // else if (subcommand.equalsIgnoreCase(F("rr")) && (argCount == 6)) - // { - // eInkScreen->drawRoundRect(sParams[0].toInt(), - // sParams[1].toInt(), - // sParams[2].toInt(), - // sParams[3].toInt(), - // sParams[4].toInt(), - // Plugin_096_ParseColor(sParams[5])); - // } - // else if (subcommand.equalsIgnoreCase(F("rrf")) && (argCount == 7)) - // { - // eInkScreen->fillRoundRect(sParams[0].toInt(), - // sParams[1].toInt(), - // sParams[2].toInt(), - // sParams[3].toInt(), - // sParams[4].toInt(), - // Plugin_096_ParseColor(sParams[6])); - // eInkScreen->drawRoundRect(sParams[0].toInt(), - // sParams[1].toInt(), - // sParams[2].toInt(), - // sParams[3].toInt(), - // sParams[4].toInt(), - // Plugin_096_ParseColor(sParams[5])); - // } - // else if (subcommand.equalsIgnoreCase(F("px")) && (argCount == 3)) - // { - // eInkScreen->drawPixel(sParams[0].toInt(), sParams[1].toInt(), Plugin_096_ParseColor(sParams[2])); - // } - // else - // { - // success = false; - // } - // # endif // ifdef P096_USE_ADA_GRAPHICS - // } - // else - // { - // success = false; - // } + if (nullptr != P096_data) { + success = P096_data->plugin_write(event, string); // Write operation, handle commands } - else - { - // invalid arguments - success = false; - } - - // in case of command outside of sequence, then refresh screen - // if (success && !plugin_096_sequence_in_progress) - // { - // eInkScreen->display(); - // } - - // # ifndef BUILD_NO_DEBUG - // String log; - // log.reserve(110); // Prevent re-allocation - // log = F("P096-eInk : WRITE = "); - // log += tmpString; - // SendStatus(event, log); // Reply (echo) to sender. This will print message on browser. - // # endif // ifndef BUILD_NO_DEBUG break; } + } return success; diff --git a/src/src/PluginStructs/P096_data_struct.cpp b/src/src/PluginStructs/P096_data_struct.cpp index 60455fd7c..e8705c703 100644 --- a/src/src/PluginStructs/P096_data_struct.cpp +++ b/src/src/PluginStructs/P096_data_struct.cpp @@ -12,6 +12,9 @@ const __FlashStringHelper* EPD_type_toString(EPD_type_e device) { case EPD_type_e::EPD_IL3897: return F("IL3897 (Lolin 250 x 122px)"); case EPD_type_e::EPD_UC8151D: return F("UC8151D (212 x 104px)"); case EPD_type_e::EPD_SSD1680: return F("SSD1680 (250 x 212px)"); + # if P096_USE_WAVESHARE_2IN7 + case EPD_type_e::EPD_WS2IN7: return F("Waveshare 2.7\" (264 x 176px)"); + # endif // if P096_USE_WAVESHARE_2IN7 case EPD_type_e::EPD_MAX: break; } return F("Unsupported type!"); @@ -27,6 +30,9 @@ const __FlashStringHelper* P096_CommandTrigger_toString(P096_CommandTrigger cmd) case P096_CommandTrigger::il3897: return F("il3897"); case P096_CommandTrigger::uc8151d: return F("uc8151d"); case P096_CommandTrigger::ssd1680: return F("ssd1680"); + # if P096_USE_WAVESHARE_2IN7 + case P096_CommandTrigger::ws2in7: return F("ws2in7"); + # endif // if P096_USE_WAVESHARE_2IN7 case P096_CommandTrigger::MAX: return F("None"); case P096_CommandTrigger::epd: break; } @@ -47,6 +53,12 @@ void EPD_type_toResolution(EPD_type_e device, uint16_t& x, uint16_t& y) { x = 212; y = 104; break; + # if P096_USE_WAVESHARE_2IN7 + case EPD_type_e::EPD_WS2IN7: + x = 264; + y = 176; + break; + # endif // if P096_USE_WAVESHARE_2IN7 case EPD_type_e::EPD_MAX: break; } @@ -120,6 +132,11 @@ bool P096_data_struct::plugin_init(struct EventStruct *event) { case EPD_type_e::EPD_SSD1680: eInkScreen = new (std::nothrow) LOLIN_SSD1680(_xpix, _ypix, PIN(1), PIN(2), PIN(0), PIN(3)); // HSPI break; + # if P096_USE_WAVESHARE_2IN7 + case EPD_type_e::EPD_WS2IN7: + eInkScreen = new (std::nothrow) Waveshare_2in7(_xpix, _ypix, PIN(1), PIN(2), PIN(0), PIN(3)); // HSPI + break; + # endif // if P096_USE_WAVESHARE_2IN7 case EPD_type_e::EPD_MAX: break; } @@ -202,6 +219,7 @@ void P096_data_struct::updateFontMetrics() { gfxHelper->getTextMetrics(_textcols, _textrows, _fontwidth, _fontheight, _fontscaling, _heightOffset, _xpix, _ypix); gfxHelper->getColors(_fgcolor, _bgcolor); } else { + if (_fontscaling == 0) { _fontscaling = 1; } _textcols = _xpix / (_fontwidth * _fontscaling); _textrows = _ypix / (_fontheight * _fontscaling); } diff --git a/src/src/PluginStructs/P096_data_struct.h b/src/src/PluginStructs/P096_data_struct.h index adfe6460e..6858437d4 100644 --- a/src/src/PluginStructs/P096_data_struct.h +++ b/src/src/PluginStructs/P096_data_struct.h @@ -4,15 +4,19 @@ #include "../../_Plugin_Helper.h" #ifdef USES_P096 -# include // include Adafruit graphics library -# include // include Adafruit Lolin eInk/ePaper library +# include // include Adafruit graphics library +# include // include Adafruit Lolin eInk/ePaper library -# define P096_USE_ADA_GRAPHICS // Use AdafruitGFX_helper +# define P096_USE_ADA_GRAPHICS // Use AdafruitGFX_helper # ifndef P096_USE_EXTENDED_SETTINGS -# define P096_USE_EXTENDED_SETTINGS 1 // Allow more settings/options, made available by the AdaGFX helper +# define P096_USE_EXTENDED_SETTINGS 1 // Allow more settings/options, made available by the AdaGFX helper # endif // ifndef P096_USE_EXTENDED_SETTINGS +# if !P096_USE_WAVESHARE_2IN7 +# define P096_USE_WAVESHARE_2IN7 1 // Include the Waveshare 2.7 inch ePaper display +# endif // if !P096_USE_WAVESHARE_2IN7 + # include "../Helpers/AdafruitGFX_helper.h" // Use Adafruit graphics helper objecr # include "../CustomBuild/StorageLayout.h" @@ -64,19 +68,25 @@ # endif // ifdef ESP32 enum class EPD_type_e : uint8_t { - EPD_IL3897 = 0, - EPD_UC8151D, - EPD_SSD1680, + EPD_IL3897 = 0u, + EPD_UC8151D = 1u, + EPD_SSD1680 = 2u, + # if P096_USE_WAVESHARE_2IN7 + EPD_WS2IN7 = 3u, + # endif // if P096_USE_WAVESHARE_2IN7 EPD_MAX // must be last value in enum }; enum class P096_CommandTrigger : uint8_t { - epd = 0u, - eInk, - ePaper, - il3897, - uc8151d, - ssd1680, + epd = 0u, + eInk = 1u, + ePaper = 2u, + il3897 = 3u, + uc8151d = 4u, + ssd1680 = 5u, + # if P096_USE_WAVESHARE_2IN7 + ws2in7 = 6u, + # endif // if P096_USE_WAVESHARE_2IN7 MAX // Keep as last item! };