mirror of
https://github.com/esphome/esphome.git
synced 2026-10-22 05:46:12 +00:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78c8d04b0d | ||
|
|
e01b244c5f | ||
|
|
017e379c87 | ||
|
|
476b442cd0 | ||
|
|
49ab7d058a | ||
|
|
3f7ec21717 | ||
|
|
b89f20cec5 | ||
|
|
fa04972a26 | ||
|
|
99b5d4a35a |
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user