mirror of
https://github.com/esphome/esphome.git
synced 2026-10-16 03:02:51 +00:00
[epaper_spi] Pass bits per pixel and plane count to the base constructor (#20683)
Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com>
This commit is contained in:
co-authored by
clydebarrow
parent
8d963bde5b
commit
ecd5980c5d
@@ -468,7 +468,7 @@ void HOT EPaperBase::draw_pixels_at(int x_start, int y_start, int w, int h, cons
|
||||
ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
|
||||
size_t contiguous_length;
|
||||
uint8_t *contiguous = this->buffer_.get_span(0, contiguous_length);
|
||||
if (!this->buffer_is_mono() || this->get_clipping().is_set() || bitness != COLOR_BITNESS_565 ||
|
||||
if (!this->buffer_is_mono_() || this->get_clipping().is_set() || bitness != COLOR_BITNESS_565 ||
|
||||
contiguous_length != this->buffer_length_) {
|
||||
Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad);
|
||||
return;
|
||||
|
||||
@@ -38,15 +38,18 @@ class EPaperBase : public Display,
|
||||
spi::DATA_RATE_2MHZ> {
|
||||
public:
|
||||
EPaperBase(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence = nullptr,
|
||||
size_t init_sequence_length = 0, DisplayType display_type = DISPLAY_TYPE_BINARY)
|
||||
size_t init_sequence_length = 0, DisplayType display_type = DISPLAY_TYPE_BINARY,
|
||||
uint8_t bits_per_pixel = 1, uint8_t planes = 1)
|
||||
: name_(name),
|
||||
width_(width),
|
||||
row_width_((width * bits_per_pixel + 7) / 8),
|
||||
height_(height),
|
||||
bits_per_pixel_(bits_per_pixel),
|
||||
planes_(planes),
|
||||
init_sequence_(init_sequence),
|
||||
init_sequence_length_(init_sequence_length),
|
||||
display_type_(display_type) {
|
||||
this->row_width_ = (this->width_ + 7) / 8; // width of a row in bytes
|
||||
}
|
||||
display_type_(display_type),
|
||||
buffer_length_((size_t) this->row_width_ * height * planes) {}
|
||||
void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; }
|
||||
float get_setup_priority() const override;
|
||||
void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; }
|
||||
@@ -134,8 +137,8 @@ class EPaperBase : public Display,
|
||||
bool rotate_coordinates_(int &x, int &y);
|
||||
void draw_rgb565_block_(uint8_t *buffer, int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
|
||||
bool big_endian, int x_offset, int y_offset, int x_pad);
|
||||
// Whether the buffer holds 1 bit per pixel as draw_pixel_at() writes it, so draw_pixels_at() can write it directly
|
||||
virtual bool buffer_is_mono() const { return false; }
|
||||
// Whether the buffer is a single plane of 1 bit per pixel, as draw_pixel_at() writes it
|
||||
bool buffer_is_mono_() const { return this->bits_per_pixel_ == 1 && this->planes_ == 1; }
|
||||
|
||||
/**
|
||||
* Methods that must be implemented by concrete classes to control the display
|
||||
@@ -173,13 +176,15 @@ class EPaperBase : public Display,
|
||||
// properties initialised in the constructor
|
||||
const char *name_;
|
||||
uint16_t width_;
|
||||
uint16_t row_width_; // width of a row in bytes
|
||||
uint16_t row_width_; // width of a row of one plane in bytes
|
||||
uint16_t height_;
|
||||
uint8_t bits_per_pixel_;
|
||||
uint8_t planes_; // the buffer holds this many planes of row_width_ * height_ bytes, one after another
|
||||
const uint8_t *init_sequence_;
|
||||
size_t init_sequence_length_;
|
||||
DisplayType display_type_;
|
||||
|
||||
size_t buffer_length_{};
|
||||
size_t buffer_length_;
|
||||
size_t current_data_index_{}; // used by data transfer to track progress
|
||||
split_buffer::SplitBuffer buffer_{};
|
||||
GPIOPin *dc_pin_{};
|
||||
|
||||
@@ -15,9 +15,7 @@ class EPaper4bpp : public EPaperBase {
|
||||
public:
|
||||
EPaper4bpp(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length)
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR) {
|
||||
this->buffer_length_ = width * height / 2; // 2 pixels per byte
|
||||
}
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR, 4) {}
|
||||
|
||||
void fill(Color color) override;
|
||||
void clear() override;
|
||||
|
||||
@@ -9,10 +9,7 @@ class EPaperInkplate2 final : public EPaperBase {
|
||||
public:
|
||||
EPaperInkplate2(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length)
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR) {
|
||||
// Dual-plane buffer: black/white plane followed by red plane, 1 bit per pixel each.
|
||||
this->buffer_length_ = this->row_width_ * this->height_ * 2;
|
||||
}
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR, 1, 2) {}
|
||||
|
||||
void fill(Color color) override;
|
||||
void clear() override;
|
||||
|
||||
@@ -27,12 +27,9 @@ class EPaperJD79660 final : public EPaperBase {
|
||||
public:
|
||||
EPaperJD79660(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length, const uint8_t *fast_update, uint16_t fast_update_length)
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR),
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR, 2),
|
||||
fast_update_(fast_update),
|
||||
fast_update_length_(fast_update_length) {
|
||||
this->row_width_ = (width + 3) / 4; // Fix base class calc (2bpp instead of 1bpp)
|
||||
this->buffer_length_ = this->row_width_ * height;
|
||||
}
|
||||
fast_update_length_(fast_update_length) {}
|
||||
|
||||
void fill(Color color) override;
|
||||
|
||||
|
||||
@@ -9,13 +9,10 @@ namespace esphome::epaper_spi {
|
||||
class EPaperMono : public EPaperBase {
|
||||
public:
|
||||
EPaperMono(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length, DisplayType display_type = DISPLAY_TYPE_BINARY)
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, display_type) {
|
||||
this->buffer_length_ = (width + 7) / 8 * height; // 8 pixels per byte, rounded up
|
||||
}
|
||||
size_t init_sequence_length, DisplayType display_type = DISPLAY_TYPE_BINARY, uint8_t bits_per_pixel = 1)
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, display_type, bits_per_pixel) {}
|
||||
|
||||
protected:
|
||||
bool buffer_is_mono() const override { return true; }
|
||||
void refresh_screen(bool partial) override;
|
||||
void power_on() override {}
|
||||
void power_off() override{};
|
||||
|
||||
@@ -58,9 +58,9 @@ bool HOT EPaperSSD1677::transfer_data() {
|
||||
// A full update ignores 0x26, and the copy may not hold a real frame yet (first update after
|
||||
// boot): send the new frame to both planes.
|
||||
const bool send_copy = this->plane_ == 0 && this->update_count_ != 0;
|
||||
// A mono buffer already holds the frame as a RAM plane does, so it can be sent as it is; a deeper
|
||||
// buffer (the four-level model) returns false and packs the plane in plane_row().
|
||||
const bool direct = send_copy || this->buffer_is_mono();
|
||||
// A 1 bit per pixel buffer already holds the frame as a RAM plane does, so it can be sent as it is; a
|
||||
// deeper buffer (the four-level model, 2 bits per pixel) packs the plane in plane_row() instead.
|
||||
const bool direct = send_copy || this->buffer_is_mono_();
|
||||
const auto &source = send_copy ? this->sent_ : this->buffer_;
|
||||
const size_t row_length = this->plane_row_length_();
|
||||
const size_t plane_length = row_length * this->height_;
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace esphome::epaper_spi {
|
||||
class EPaperSSD1677 : public EPaperMono {
|
||||
public:
|
||||
EPaperSSD1677(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length, DisplayType display_type = DISPLAY_TYPE_BINARY)
|
||||
: EPaperMono(name, width, height, init_sequence, init_sequence_length, display_type) {}
|
||||
size_t init_sequence_length, DisplayType display_type = DISPLAY_TYPE_BINARY, uint8_t bits_per_pixel = 1)
|
||||
: EPaperMono(name, width, height, init_sequence, init_sequence_length, display_type, bits_per_pixel) {}
|
||||
|
||||
void setup() override;
|
||||
|
||||
|
||||
@@ -29,16 +29,12 @@ class EPaperSSD1677Gray4 : public EPaperSSD1677 {
|
||||
public:
|
||||
EPaperSSD1677Gray4(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length)
|
||||
: EPaperSSD1677(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_GRAYSCALE) {
|
||||
this->row_width_ = (width + 3) / 4; // 4 pixels per byte
|
||||
this->buffer_length_ = (size_t) this->row_width_ * height;
|
||||
}
|
||||
: EPaperSSD1677(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_GRAYSCALE, 2) {}
|
||||
|
||||
void fill(Color color) override;
|
||||
void draw_pixel_at(int x, int y, Color color) override;
|
||||
|
||||
protected:
|
||||
bool buffer_is_mono() const override { return false; }
|
||||
// A partial update if partial updates are enabled and this is not a full one.
|
||||
bool is_partial_push_() const { return this->update_count_ != 0 && this->sent_.is_valid(); }
|
||||
void plane_row(size_t y, uint8_t *out) override;
|
||||
|
||||
@@ -22,9 +22,7 @@ class EPaperT133A01 : public EPaperBase {
|
||||
public:
|
||||
EPaperT133A01(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length)
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR) {
|
||||
this->buffer_length_ = (size_t) width * height / 2; // 2 pixels per byte at 4bpp
|
||||
}
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR, 4) {}
|
||||
|
||||
void set_cs_pins(GPIOPin *cs, GPIOPin *cs1) {
|
||||
this->cs_pin_ = cs;
|
||||
|
||||
@@ -32,12 +32,9 @@ class EPaperUC8179 final : public EPaperBase {
|
||||
public:
|
||||
EPaperUC8179(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length)
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_BINARY) {
|
||||
this->buffer_length_ = this->row_width_ * height;
|
||||
}
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_BINARY) {}
|
||||
|
||||
protected:
|
||||
bool buffer_is_mono() const override { return true; }
|
||||
bool initialise(bool partial) override;
|
||||
bool transfer_data() override;
|
||||
void refresh_screen(bool partial) override;
|
||||
|
||||
@@ -22,9 +22,7 @@ class EPaperWaveshareBWR : public EPaperBase {
|
||||
public:
|
||||
EPaperWaveshareBWR(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length)
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_BINARY) {
|
||||
this->buffer_length_ = this->row_width_ * height * 2;
|
||||
}
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_BINARY, 1, 2) {}
|
||||
|
||||
void fill(Color color) override;
|
||||
|
||||
|
||||
@@ -18,9 +18,7 @@ class EPaperWeAct3C : public EPaperBase {
|
||||
public:
|
||||
EPaperWeAct3C(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length)
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_BINARY) {
|
||||
this->buffer_length_ = this->row_width_ * height * 2;
|
||||
}
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_BINARY, 1, 2) {}
|
||||
|
||||
void fill(Color color) override;
|
||||
void clear() override;
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "esphome/components/epaper_spi/epaper_spi_ssd1677_gray4.h"
|
||||
#include "esphome/components/epaper_spi/epaper_spi_ssd1683.h"
|
||||
#include "esphome/components/epaper_spi/epaper_spi_t133a01.h"
|
||||
#include "esphome/components/epaper_spi/epaper_waveshare_bwr.h"
|
||||
#include "esphome/components/epaper_spi/epaper_weact_3c.h"
|
||||
|
||||
namespace esphome::epaper_spi::testing {
|
||||
namespace {
|
||||
|
||||
template<typename Driver> class Layout : public Driver {
|
||||
public:
|
||||
Layout(uint16_t width, uint16_t height) : Driver("test", width, height, nullptr, 0) {}
|
||||
uint16_t row_width() const { return this->row_width_; }
|
||||
size_t buffer_length() const { return this->buffer_length_; }
|
||||
bool is_mono() const { return this->buffer_is_mono_(); }
|
||||
};
|
||||
|
||||
/// Each driver's bits per pixel and plane count give the row width and buffer size its drawing code expects, and only
|
||||
/// a single 1 bit per pixel plane takes the direct drawing paths.
|
||||
TEST(EPaperBufferLayout, SizesFollowBitsPerPixelAndPlanes) {
|
||||
Layout<EPaperSSD1683> mono(21, 3);
|
||||
EXPECT_EQ(mono.row_width(), 3);
|
||||
EXPECT_EQ(mono.buffer_length(), 9u);
|
||||
EXPECT_TRUE(mono.is_mono());
|
||||
|
||||
Layout<EPaperSSD1677Gray4> gray(21, 3);
|
||||
EXPECT_EQ(gray.row_width(), 6);
|
||||
EXPECT_EQ(gray.buffer_length(), 18u);
|
||||
EXPECT_FALSE(gray.is_mono());
|
||||
|
||||
Layout<EPaperT133A01> t133(20, 3);
|
||||
EXPECT_EQ(t133.row_width(), 10);
|
||||
EXPECT_EQ(t133.buffer_length(), 30u);
|
||||
EXPECT_FALSE(t133.is_mono());
|
||||
|
||||
Layout<EPaperWeAct3C> weact(21, 3);
|
||||
EXPECT_EQ(weact.row_width(), 3);
|
||||
EXPECT_EQ(weact.buffer_length(), 18u);
|
||||
EXPECT_FALSE(weact.is_mono());
|
||||
|
||||
Layout<EPaperWaveshareBWR> bwr(21, 3);
|
||||
EXPECT_EQ(bwr.buffer_length(), 18u);
|
||||
EXPECT_FALSE(bwr.is_mono());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace esphome::epaper_spi::testing
|
||||
Reference in New Issue
Block a user