11static constexpr size_t EPAPER_MAX_CMD_LOG_BYTES = 128;
13static constexpr const char *
const EPAPER_STATE_STRINGS[] = {
14 "IDLE",
"UPDATE",
"RESET",
"RESET_END",
"SHOULD_WAIT",
"INITIALISE",
15 "TRANSFER_DATA",
"POWER_ON",
"REFRESH_SCREEN",
"POWER_OFF",
"DEEP_SLEEP",
19 if (
auto idx =
static_cast<unsigned>(this->
state_); idx < std::size(EPAPER_STATE_STRINGS))
20 return EPAPER_STATE_STRINGS[idx];
26 this->
mark_failed(LOG_STR(
"Failed to initialise buffer"));
46 ESP_LOGW(TAG,
"No memory for the previous frame; partial updates will send the whole drawn area");
56 for (
size_t i = 0; i !=
length; i++)
80 pin->digital_write(
true);
98 ESP_LOGV(TAG,
"Command: 0x%02X", value);
107#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
109 ESP_LOGV(TAG,
"Command: 0x%02X, Length: %d, Data: %s",
command,
length,
167#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
202#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
211 if (busy_for > FAST_BUSY_POLL_MS)
213#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
229 ESP_LOGE(TAG,
"Display stayed busy for %u s in state %s; check the busy pin", (
unsigned) this->
busy_timeout_seconds_,
282 ESP_LOGD(TAG,
"Frame unchanged, refresh skipped");
307 if (this->
sent_.
is_valid() && this->sent_count_ == this->sent_.size())
376 this->
mark_failed(LOG_STR(
"Malformed init sequence"));
379 const uint8_t cmd = sequence[index++];
380 if (
const uint8_t
x = sequence[index++];
x == DELAY_FLAG) {
381 ESP_LOGV(TAG,
"Delay %dms", cmd);
384 const uint8_t num_args =
x & 0x7F;
385 if (
length - index < num_args) {
386 ESP_LOGE(TAG,
"Malformed init sequence, cmd = %X, num_args = %u", cmd, num_args);
390 this->
cmd_data(cmd, sequence + index, num_args);
435 const size_t byte_position =
y * this->
row_width_ + x / 8;
436 const uint8_t bit_position =
x % 8;
437 const uint8_t pixel_bit = 0x80u >> bit_position;
438 const auto original = this->
buffer_[byte_position];
440 this->
buffer_[byte_position] = original & ~pixel_bit;
442 this->
buffer_[byte_position] = original | pixel_bit;
450template<
bool SwapAxes,
bool BigEndianSource>
451void HOT write_rgb565_row(uint8_t *
byte, uint8_t mask,
int step,
size_t row_width,
const uint8_t *source,
int count,
453 const ptrdiff_t byte_step = SwapAxes ? step *
static_cast<ptrdiff_t
>(row_width) : 0;
456 if (to_mono(value)) {
461 if constexpr (SwapAxes) {
463 }
else if (step > 0) {
488 const int column_limit = swap ? this->
height_ : this->
width_;
490 const bool column_mirrored = swap ? mirror_y : mirror_x;
491 const bool row_mirrored = swap ? mirror_x : mirror_y;
492 const int first_column = std::max(0, -
x_start);
493 const int end_column = std::min(
w, column_limit -
x_start);
494 const int first_row = std::max(0, -
y_start);
495 const int end_row = std::min(
h, row_limit -
y_start);
496 if (first_column >= end_column || first_row >= end_row)
498 auto column_to_buffer = [&](
int column) {
499 const int u =
x_start + column;
500 return column_mirrored ? column_limit - 1 - u : u;
502 auto row_to_buffer = [&](
int row) {
504 return row_mirrored ? row_limit - 1 - v : v;
507 const int column_low = std::min(column_to_buffer(first_column), column_to_buffer(end_column - 1));
508 const int row_low = std::min(row_to_buffer(first_row), row_to_buffer(end_row - 1));
509 const int columns = end_column - first_column;
510 const int rows = end_row - first_row;
511 const int x_low = swap ? row_low : column_low;
512 const int y_low = swap ? column_low : row_low;
513 const int x_high = x_low + (swap ? rows : columns);
514 const int y_high = y_low + (swap ? columns : rows);
519 const int step = column_mirrored ? -1 : 1;
520 for (
int row = first_row; row != end_row; row++) {
521 const uint8_t *source =
ptr + ((
y_offset + row) * line_stride +
x_offset + first_column) * 2;
522 const int along = column_to_buffer(first_column);
523 const int across = row_to_buffer(row);
524 const int x = swap ? across : along;
525 const int y = swap ? along : across;
526 uint8_t *
byte =
buffer +
y * row_width +
x / 8;
527 const uint8_t mask = 0x80u >> (
x % 8);
530 write_rgb565_row<true, true>(
byte, mask, step, row_width, source, columns, to_mono);
532 write_rgb565_row<true, false>(
byte, mask, step, row_width, source, columns, to_mono);
535 write_rgb565_row<false, true>(
byte, mask, step, row_width, source, columns, to_mono);
537 write_rgb565_row<false, false>(
byte, mask, step, row_width, source, columns, to_mono);
552 size_t contiguous_length;
563 LOG_DISPLAY(
"",
"E-Paper SPI",
this);
566 " SPI Data Rate: %uMHz\n"
567 " Full update every: %d\n"
575 LOG_PIN(
" DC Pin: ", this->
dc_pin_);
577 LOG_PIN(
" CS Pin: ", this->
cs_);
578 LOG_UPDATE_INTERVAL(
this);
uint32_t get_loop_interval() const
void mark_failed()
Mark this component as failed.
void status_set_warning()
void enable_loop()
Enable this component's loop.
void disable_loop()
Disable this component's loop.
void status_clear_warning()
virtual void digital_write(bool value)=0
virtual bool digital_read()=0
void stop()
Stop running the loop continuously.
void start()
Start running the loop continuously.
int int int const uint8_t ColorOrder ColorBitness bitness
int int int const uint8_t ColorOrder ColorBitness bool int int y_offset
int int int const uint8_t ColorOrder ColorBitness bool int int int x_pad
int int int const uint8_t * ptr
bool ESPHOME_ALWAYS_INLINE is_point_clipped(int x, int y) const
Whether (x, y) falls outside the active clipping rectangle.
int int int const uint8_t ColorOrder ColorBitness bool big_endian
Rect get_clipping() const
Get the current the clipping rectangle.
int int int const uint8_t ColorOrder ColorBitness bool int x_offset
DisplayRotation rotation_
virtual void draw_pixels_internal(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad)
Draws a block for draw_pixels_at(); the parameters are the same.
color_to_mono() of an RGB565 value as ColorUtil::to_color() reads it, from table lookups instead of a...
uint32_t update_start_time_
virtual void power_off()=0
Power the display off.
void command(uint8_t value)
virtual void abort_transfer()
const uint8_t * init_sequence_
void process_state_()
Process the state machine.
virtual void deep_sleep()=0
Place the display into deep sleep.
bool is_using_partial_update_() const
void on_safe_shutdown() override
void draw_pixel_at(int x, int y, Color color) override
Default implementation for monochrome displays where 8 pixels are packed to a byte.
bool init_sent_frame_(size_t length)
virtual bool after_refresh()
Called after the refresh, before power off, repeatedly until it returns true.
uint32_t waiting_for_idle_start_
bool rotate_coordinates_(int &x, int &y)
Check and rotate coordinates based on the transform flags.
void loop() override
Called during the loop task.
virtual void refresh_screen(bool partial)=0
Refresh the screen after data transfer.
uint8_t full_update_every_
virtual bool initialise(bool partial)
void send_init_sequence_(const uint8_t *sequence, size_t length)
void dump_config() override
void update_effective_transform_()
uint32_t buffer_hash_() const
virtual bool transfer_data()=0
Methods that must be implemented by concrete classes to control the display.
bool buffer_is_mono_() const
split_buffer::SplitBuffer buffer_
void cmd_data(uint8_t command, const uint8_t *ptr, size_t length)
void draw_rgb565_block_(uint8_t *buffer, int x_start, int y_start, int w, int h, const uint8_t *ptr, bool big_endian, int x_offset, int y_offset, int x_pad)
bool full_update_requested_
uint16_t busy_timeout_seconds_
split_buffer::SplitBuffer sent_
void set_state_(EPaperState state, uint16_t delay=0)
const char * epaper_state_to_string_()
uint8_t effective_transform_
virtual void power_on()=0
Power the display on.
HighFrequencyLoopRequester high_frequency_loop_
void draw_pixels_internal(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override
void wait_for_idle_(bool should_wait)
bool hardware_reset_()
The reset pin part of reset(), for a driver that must skip what its parent adds to it.
size_t current_data_index_
uint32_t waiting_for_idle_last_print_
size_t init_sequence_length_
float get_setup_priority() const override
bool init_buffer_(size_t buffer_length)
std::vector< GPIOPin * > enable_pins_
void spi_setup() override
void write_byte(uint8_t data)
void write_array(const uint8_t *data, size_t length)
bool init(size_t total_length, size_t max_buffer_size=SIZE_MAX)
const uint8_t * get_span(size_t index, size_t &length) const
@ DISPLAY_ROTATION_270_DEGREES
@ DISPLAY_ROTATION_180_DEGREES
@ DISPLAY_ROTATION_90_DEGREES
static void int int int int const uint8_t ColorOrder ColorBitness bool big_endian
static void int int int int const uint8_t ColorOrder ColorBitness bitness
static void int int int int const uint8_t int x_offset
static void int int y_start
static void int int int int const uint8_t int int y_offset
static void int int int w
ESPHOME_LOG_TAG(TAG, "display")
constexpr uint8_t color_to_mono(Color color)
Map an RGB color to a single monochrome bit: 1 = white, 0 = black.
static void int int int int h
static void int int int int const uint8_t * ptr
static void int int int int const uint8_t int int int x_pad
constexpr float PROCESSOR
For components that use data from sensors like displays.
T clamp_at_most(T value, U max)
constexpr uint32_t fnv1a_hash_extend(uint32_t hash, const char *str)
Extend a FNV-1a hash with additional string data.
constexpr uint32_t FNV1_OFFSET_BASIS
FNV-1 32-bit offset basis.
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
constexpr T encode_value_le(const uint8_t *bytes)
Encode a value from its constituent bytes (from least to most significant) in an array with length si...
T clamp_at_least(T value, U min)
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
void HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.