Compare commits

...
19 changed files with 38 additions and 109 deletions
+1 -4
View File
@@ -216,10 +216,7 @@ void EPaperBase::process_state_() {
// Refresh the whole panel even if nothing was drawn
this->full_update_requested_ = false;
this->update_count_ = 0;
this->x_low_ = 0;
this->y_low_ = 0;
this->x_high_ = this->width_;
this->y_high_ = this->height_;
this->mark_all_dirty_();
}
if (this->x_high_ < this->x_low_ || this->y_high_ < this->y_low_) {
this->set_state_(EPaperState::IDLE);
+17 -12
View File
@@ -84,22 +84,15 @@ class EPaperBase : public Display,
DisplayType get_display_type() override { return this->display_type_; };
// Default implementation for monochrome displays
void fill(Color color) override {
// If clipping is active, fall back to base implementation
// Whole buffer fills bypass draw_pixel_at(), so the dirty bounds are set here once for every driver.
void fill(Color color) final {
// If clipping is active, fall back to the per-pixel base implementation
if (this->get_clipping().is_set()) {
Display::fill(color);
return;
}
auto pixel_color = color_to_mono(color) ? 0xFF : 0x00;
// We store 8 pixels per byte
this->buffer_.fill(pixel_color);
this->x_high_ = this->width_;
this->y_high_ = this->height_;
this->x_low_ = 0;
this->y_low_ = 0;
this->fill_buffer(color);
this->mark_all_dirty_();
}
void clear() override {
@@ -122,6 +115,18 @@ class EPaperBase : public Display,
int get_height_internal() override { return this->height_; };
int get_width_internal() override { return this->width_; };
bool is_using_partial_update_() const { return this->full_update_every_ > 1; }
/// Fill the whole frame buffer with the color.
virtual void fill_buffer(Color color) {
// We store 8 pixels per byte
this->buffer_.fill(color_to_mono(color) ? 0xFF : 0x00);
}
/// An update with no dirty area is skipped, so whole buffer writes must call this.
void mark_all_dirty_() {
this->x_low_ = 0;
this->y_low_ = 0;
this->x_high_ = this->width_;
this->y_high_ = this->height_;
}
void process_state_();
const char *epaper_state_to_string_();
@@ -6,28 +6,11 @@ namespace esphome::epaper_spi {
ESPHOME_LOG_TAG(TAG, "epaper_spi.4bpp");
void EPaper4bpp::fill(Color color) {
// If clipping is active, fall back to base implementation
if (this->get_clipping().is_set()) {
EPaperBase::fill(color);
return;
}
void EPaper4bpp::fill_buffer(Color color) {
auto pixel_color = this->color_to_native(color);
// We store 2 pixels per byte
this->buffer_.fill(pixel_color + (pixel_color << 4));
// Whole buffer just changed; mark the entire canvas dirty.
this->x_low_ = 0;
this->y_low_ = 0;
this->x_high_ = this->width_;
this->y_high_ = this->height_;
}
void EPaper4bpp::clear() {
// clear buffer to white, just like real paper.
this->fill(COLOR_ON);
}
void HOT EPaper4bpp::draw_pixel_at(int x, int y, Color color) {
@@ -7,7 +7,7 @@ namespace esphome::epaper_spi {
/**
* Intermediate base for panels with a 4-bit-per-pixel native buffer layout (2 pixels per byte).
*
* Owns buffer sizing, fill()/clear()/draw_pixel_at() and the chunked SPI transfer loop shared by
* Owns buffer sizing, fill_buffer()/draw_pixel_at() and the chunked SPI transfer loop shared by
* this family of controllers. Concrete subclasses supply only their RGB -> 4-bit color mapping via
* color_to_native() plus their IC-specific power/refresh/sleep command sequences.
*/
@@ -17,10 +17,8 @@ class EPaper4bpp : public EPaperBase {
size_t init_sequence_length)
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR, 4) {}
void fill(Color color) override;
void clear() override;
protected:
void fill_buffer(Color color) override;
void draw_pixel_at(int x, int y, Color color) override;
bool transfer_data() override;
@@ -39,12 +39,7 @@ void EPaperInkplate2::deep_sleep() {
this->cmd_data(0x07, {0xA5});
}
void EPaperInkplate2::fill(Color color) {
if (this->get_clipping().is_set()) {
EPaperBase::fill(color); // clipping active: defer to the base per-pixel path
return;
}
void EPaperInkplate2::fill_buffer(Color color) {
const size_t half_buffer = this->buffer_length_ / 2;
// Plane encoding: B/W plane 1=white, 0=black; red plane 0=red, 1=no-red.
@@ -70,22 +65,15 @@ void EPaperInkplate2::fill(Color color) {
this->buffer_[i] = bw_byte;
for (size_t i = half_buffer; i < this->buffer_length_; i++)
this->buffer_[i] = red_byte;
this->x_low_ = 0;
this->y_low_ = 0;
this->x_high_ = this->width_;
this->y_high_ = this->height_;
}
void EPaperInkplate2::clear() { this->fill(COLOR_ON); }
void HOT EPaperInkplate2::draw_pixel_at(int x, int y, Color color) {
if (!this->rotate_coordinates_(x, y))
return;
const size_t half_buffer = this->buffer_length_ / 2;
const size_t pos = y * this->row_width_ + x / 8;
const uint8_t mask = 0x80 >> (x & 0x07); // MSB first; see fill() for plane encoding
const uint8_t mask = 0x80 >> (x & 0x07); // MSB first; see fill_buffer() for plane encoding
switch (to_inkplate2_color(color)) {
case Inkplate2Color::BLACK:
@@ -11,11 +11,10 @@ class EPaperInkplate2 final : public EPaperBase {
size_t init_sequence_length)
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR, 1, 2) {}
void fill(Color color) override;
void clear() override;
void draw_pixel_at(int x, int y, Color color) override;
protected:
void fill_buffer(Color color) override;
void refresh_screen(bool partial) override;
void power_on() override;
void power_off() override;
@@ -19,13 +19,7 @@ static JD79660Color HOT color_to_hex(Color color) {
return color_to_bwyr(color, JD79660Color::BLACK, JD79660Color::WHITE, JD79660Color::YELLOW, JD79660Color::RED);
}
void EPaperJD79660::fill(Color color) {
// If clipping is active, fall back to base implementation
if (this->get_clipping().is_set()) {
EPaperBase::fill(color);
return;
}
void EPaperJD79660::fill_buffer(Color color) {
const auto pixel_color = color_to_hex(color);
// We store 4 pixels per byte
@@ -31,9 +31,8 @@ class EPaperJD79660 final : public EPaperBase {
fast_update_(fast_update),
fast_update_length_(fast_update_length) {}
void fill(Color color) override;
protected:
void fill_buffer(Color color) override;
/** Draw colored pixel into frame buffer */
void draw_pixel_at(int x, int y, Color color) override;
@@ -33,10 +33,7 @@ void EPaperMono::set_window() {
// if not using partial update, the display will go into deep sleep, so must rewrite entire
// buffer since the display RAM will not retain contents
if (!this->is_using_partial_update_()) {
this->x_low_ = 0;
this->x_high_ = this->width_;
this->y_low_ = 0;
this->y_high_ = this->height_;
this->mark_all_dirty_();
}
// round x-coordinates to byte boundaries
this->x_low_ &= ~7;
@@ -47,10 +47,7 @@ bool HOT EPaperSSD1677::transfer_data() {
const auto start_time = millis();
if (this->current_data_index_ == 0) {
if (this->plane_ == 0) {
this->x_low_ = 0;
this->x_high_ = this->width_;
this->y_low_ = 0;
this->y_high_ = this->height_;
this->mark_all_dirty_();
}
this->set_window();
this->command(this->plane_ == 0 ? 0x26 : 0x24);
@@ -21,18 +21,9 @@ static uint8_t plane_byte(uint8_t first, uint8_t second, bool high_bit) {
return out;
}
void EPaperSSD1677Gray4::fill(Color color) {
if (this->get_clipping().is_set()) {
// Falls back to the generic per-pixel implementation for the clipped rectangle.
EPaperBase::fill(color);
return;
}
void EPaperSSD1677Gray4::fill_buffer(Color color) {
const uint8_t level = color_to_gray4(color);
this->buffer_.fill((uint8_t) (level | (level << 2) | (level << 4) | (level << 6)));
this->x_low_ = 0;
this->y_low_ = 0;
this->x_high_ = this->width_;
this->y_high_ = this->height_;
}
void HOT EPaperSSD1677Gray4::draw_pixel_at(int x, int y, Color color) {
@@ -64,10 +55,7 @@ bool HOT EPaperSSD1677Gray4::transfer_data() {
if (first_pass) {
// With partial updates enabled the window follows the changed area, but the four-level
// refresh drives every pixel from both planes, and the reset before it does not keep RAM.
this->x_low_ = 0;
this->x_high_ = this->width_;
this->y_low_ = 0;
this->y_high_ = this->height_;
this->mark_all_dirty_();
this->set_window();
}
this->command(first_pass ? 0x24 : 0x26);
@@ -31,10 +31,10 @@ class EPaperSSD1677Gray4 : public EPaperSSD1677 {
size_t init_sequence_length)
: 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:
void fill_buffer(Color color) override;
// 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;
@@ -35,10 +35,7 @@ void EPaperSSD1683::set_window() {
// if not using partial update, the display will go into deep sleep mode 2, so must rewrite entire
// buffer since the display RAM will not retain contents
if (!this->is_using_partial_update_()) {
this->x_low_ = 0;
this->x_high_ = this->width_;
this->y_low_ = 0;
this->y_high_ = this->height_;
this->mark_all_dirty_();
}
// round x-coordinates to byte boundaries
@@ -225,11 +225,7 @@ void EPaperT133A01::write_command_(uint8_t command, const uint8_t *data, size_t
this->cs1_pin_->digital_write(true);
}
void EPaperT133A01::fill(Color color) {
if (this->get_clipping().is_set()) {
EPaperBase::fill(color);
return;
}
void EPaperT133A01::fill_buffer(Color color) {
auto pixel_color = color_to_index(color);
this->buffer_.fill(pixel_color + (pixel_color << 4));
}
@@ -29,13 +29,12 @@ class EPaperT133A01 : public EPaperBase {
this->cs1_pin_ = cs1;
}
void fill(Color color) override;
void setup() override;
void dump_config() override;
void draw_pixel_at(int x, int y, Color color) override;
protected:
void fill_buffer(Color color) override;
bool reset() override;
bool initialise(bool partial) override;
void refresh_screen(bool partial) override;
@@ -49,7 +49,7 @@ void EPaperWaveshareBWR::draw_pixel_at(int x, int y, Color color) {
}
}
void EPaperWaveshareBWR::fill(Color color) {
void EPaperWaveshareBWR::fill_buffer(Color color) {
const size_t half_buffer = this->buffer_length_ / 2u;
const auto bwr = color_to_bwr(color);
@@ -24,9 +24,8 @@ class EPaperWaveshareBWR : public EPaperBase {
size_t init_sequence_length)
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_BINARY, 1, 2) {}
void fill(Color color) override;
protected:
void fill_buffer(Color color) override;
void draw_pixel_at(int x, int y, Color color) override;
bool transfer_data() override;
void refresh_screen(bool partial) override;
@@ -60,7 +60,7 @@ void EPaperWeAct3C::draw_pixel_at(int x, int y, Color color) {
}
}
void EPaperWeAct3C::fill(Color color) {
void EPaperWeAct3C::fill_buffer(Color color) {
// For 3-color e-paper with 1-bit buffer format:
// - Black buffer: 1=black, 0=white
// - Red buffer: 1=red, 0=no red
@@ -89,11 +89,6 @@ void EPaperWeAct3C::fill(Color color) {
}
}
void EPaperWeAct3C::clear() {
// Clear buffer to white, just like real paper.
this->fill(COLOR_ON);
}
void EPaperWeAct3C::set_window_() {
// For full screen refresh, we always start from (0,0)
// The y_low_/y_high_ values track the dirty region for optimization,
@@ -20,10 +20,8 @@ class EPaperWeAct3C : public EPaperBase {
size_t init_sequence_length)
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_BINARY, 1, 2) {}
void fill(Color color) override;
void clear() override;
protected:
void fill_buffer(Color color) override;
void set_window_();
void refresh_screen(bool partial) override;
void power_on() override;