Display Drivers
ESPP contains a reusable set of display-controller implementations in the display_drivers component.
The drivers use the shared object-style display_drivers::Controller / display_drivers::MipiDbiDisplayDriver architecture so controller state is owned per instance instead of hidden behind static helpers.
The component also provides SpiPanelIo / SpiCommandData, a SPI-backed
implementation of the shared display_drivers::PanelIo transport interface for
command/data display panels, in components/display_drivers/include/spi_panel_io.hpp.
API Reference
Header File
Classes
-
class PanelIo
SPI/parallel/DSI panel transport interface for object-style display controllers.
Subclassed by espp::SpiPanelIo
Public Functions
-
virtual ~PanelIo() = default
Virtual destructor.
-
virtual bool initialized() const = 0
Check whether the transport has been initialized successfully.
- Returns:
True if the transport is ready for use.
-
virtual void write_command(uint8_t command, std::span<const uint8_t> parameters, uint32_t flags = 0) = 0
Send a command and optional parameter payload immediately.
- Parameters:
command – Command byte to transmit.
parameters – Optional command payload bytes.
flags – Optional transport-specific user flags.
-
virtual void queue_command(uint8_t command, uint32_t flags = 0) = 0
Queue a command byte for asynchronous transmission.
- Parameters:
command – Command byte to transmit.
flags – Optional transport-specific user flags.
-
virtual void queue_data(std::span<const uint8_t> data, uint32_t flags = 0) = 0
Queue a non-pixel data payload for asynchronous transmission.
- Parameters:
data – Payload bytes to transmit.
flags – Optional transport-specific user flags.
-
virtual void queue_pixels(const uint8_t *data, size_t size, uint32_t flags = 0, uint32_t transaction_flags = 0) = 0
Queue a pixel payload for asynchronous transmission.
- Parameters:
data – Pointer to the pixel payload.
size – Payload size in bytes.
flags – Optional transport-specific user flags.
transaction_flags – Optional low-level transaction flags.
-
virtual void wait() = 0
Wait for all queued transfers to complete.
-
virtual ~PanelIo() = default
-
class Controller
Object-style base class for display controllers.
Subclassed by espp::display_drivers::MipiDbiDisplayDriver
Public Functions
-
inline explicit Controller(const Config &config)
Construct a controller from the shared display configuration.
- Parameters:
config – Display configuration.
-
virtual ~Controller() = default
Virtual destructor.
-
virtual bool initialize() = 0
Initialize the concrete display controller.
- Returns:
True on success.
-
inline virtual void set_rotation(const DisplayRotation &rotation)
Update the controller rotation state.
- Parameters:
rotation – New display rotation.
-
inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
Write an area of pixel data without implicitly notifying LVGL.
- Parameters:
disp – LVGL display pointer, used when synchronous flush completion is needed.
area – Area to update.
color_map – Pixel buffer for the area.
flags – Transport/user flags passed through to the write path.
-
inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
Flush an area of pixel data and notify LVGL when appropriate.
- Parameters:
disp – LVGL display pointer.
area – Area to flush.
color_map – Pixel buffer for the area.
-
virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) = 0
Clear a rectangular region to a solid color.
- Parameters:
x – Starting X coordinate.
y – Starting Y coordinate.
width – Width in pixels.
height – Height in pixels.
color – RGB565 color value.
-
inline virtual void set_offset(int x, int y)
Update the controller’s logical top-left pixel offset.
- Parameters:
x – X offset in pixels.
y – Y offset in pixels.
-
inline virtual void get_offset(int &x, int &y) const
Read the controller’s logical top-left pixel offset.
- Parameters:
x – Filled with the current X offset.
y – Filled with the current Y offset.
-
inline explicit Controller(const Config &config)
-
class MipiDbiDisplayDriver : public espp::display_drivers::Controller
Shared base for command/data/window-based MIPI DBI panels.
Subclassed by espp::Gc9a01, espp::Ili9341, espp::Ili9881, espp::Sh8601, espp::Ssd1351, espp::St7123, espp::St7789, espp::St7796
Public Functions
-
inline explicit MipiDbiDisplayDriver(const Config &config, const Protocol &protocol)
Construct a shared MIPI DBI-style controller base.
- Parameters:
config – Shared display configuration.
protocol – Controller-specific command mapping.
-
inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override
Clear a rectangular region to a solid color.
- Parameters:
x – Starting X coordinate.
y – Starting Y coordinate.
width – Width in pixels.
height – Height in pixels.
color – RGB565 color value.
-
virtual bool initialize() = 0
Initialize the concrete display controller.
- Returns:
True on success.
-
inline virtual void set_rotation(const DisplayRotation &rotation)
Update the controller rotation state.
- Parameters:
rotation – New display rotation.
-
inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
Write an area of pixel data without implicitly notifying LVGL.
- Parameters:
disp – LVGL display pointer, used when synchronous flush completion is needed.
area – Area to update.
color_map – Pixel buffer for the area.
flags – Transport/user flags passed through to the write path.
-
inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
Flush an area of pixel data and notify LVGL when appropriate.
- Parameters:
disp – LVGL display pointer.
area – Area to flush.
color_map – Pixel buffer for the area.
-
inline virtual void set_offset(int x, int y)
Update the controller’s logical top-left pixel offset.
- Parameters:
x – X offset in pixels.
y – Y offset in pixels.
-
inline virtual void get_offset(int &x, int &y) const
Read the controller’s logical top-left pixel offset.
- Parameters:
x – Filled with the current X offset.
y – Filled with the current Y offset.
-
struct Protocol
DBI protocol commands used by a concrete controller.
-
inline explicit MipiDbiDisplayDriver(const Config &config, const Protocol &protocol)
Header File
Classes
-
class Gc9a01 : public espp::display_drivers::MipiDbiDisplayDriver
Display driver for the GC9A01 display controller.
SmartKnob Config
static constexpr std::string_view dev_kit = "Smartknob-HA"; int clock_speed = 80 * 1000 * 1000; gpio_num_t mosi = GPIO_NUM_6; gpio_num_t sclk = GPIO_NUM_5; gpio_num_t spics = GPIO_NUM_15; gpio_num_t reset = GPIO_NUM_4; gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM; gpio_num_t backlight = GPIO_NUM_7; size_t width = 240; size_t height = 240; size_t pixel_buffer_size = width * 50; bool backlight_on_value = true; bool reset_value = false; bool invert_colors = true; int offset_x = 0; int offset_y = 0; bool mirror_x = true; bool mirror_y = true; auto rotation = espp::DisplayRotation::LANDSCAPE;
Gc9a01 Example
spi_bus = std::make_unique<espp::Spi>(espp::Spi::Config{ .host = spi_num, .sclk_io_num = sclk, .mosi_io_num = mosi, #ifdef CONFIG_DISPLAY_QUAD_SPI .miso_io_num = miso, .quadwp_io_num = data2, .quadhd_io_num = data3, #else .miso_io_num = GPIO_NUM_NC, #endif .max_transfer_sz = SPI_MAX_TRANSFER_BYTES, }); if (!spi_bus->initialized()) { fmt::print("Failed to initialize SPI bus\n"); return; } #ifdef CONFIG_DISPLAY_QUAD_SPI std::error_code ec; spi_device = spi_bus->add_device( espp::Spi::DeviceConfig{ .command_bits = 8, .address_bits = 24, .mode = 0, .clock_speed_hz = clock_speed, .input_delay_ns = 0, .cs_io_num = spics, .queue_size = spi_queue_size, .flags = SPI_DEVICE_HALFDUPLEX, #ifndef CONFIG_T_ENCODER_PRO .pre_cb = lcd_spi_pre_transfer_callback, #endif .post_cb = lcd_spi_post_transfer_callback, }, ec); if (ec || !spi_device) { fmt::print("Failed to initialize SPI device: {}\n", ec.message()); return; } #else panel_io = std::make_unique<espp::SpiPanelIo>(espp::SpiPanelIo::Config{ .spi = spi_bus.get(), .device_config = { .mode = 0, .clock_speed_hz = clock_speed, .input_delay_ns = 0, .cs_io_num = spics, .queue_size = spi_queue_size, #ifdef CONFIG_HARDWARE_BYTE90 .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_3WIRE, #endif }, .data_command_io = dc_pin, .data_command_bit_mask = DC_LEVEL_BIT, .post_transaction_callback_bit_mask = FLUSH_BIT, .post_transaction_callback = lcd_spi_flush_ready, }); if (!panel_io->initialized()) { fmt::print("Failed to initialize SPI panel I/O\n"); return; } #endif auto display_driver = std::make_shared<DisplayDriver>(espp::display_drivers::Config{ .panel_io = #ifdef CONFIG_DISPLAY_QUAD_SPI nullptr, .write_command = write_command, #else panel_io.get(), .write_command = nullptr, #endif .read_command = nullptr, #ifdef CONFIG_DISPLAY_QUAD_SPI .lcd_send_lines = lcd_send_lines, #else .lcd_send_lines = nullptr, #endif .reset_pin = reset, #ifndef CONFIG_T_ENCODER_PRO .data_command_pin = dc_pin, #endif .reset_value = reset_value, .invert_colors = invert_colors, .offset_x = offset_x, .offset_y = offset_y, .mirror_x = mirror_x, .mirror_y = mirror_y, }); display_driver->initialize(); // initialize the display / lvgl auto display = std::make_shared<Display>( Display::LvglConfig{ .width = width, .height = height, .flush_callback = [display_driver](lv_display_t *disp, const lv_area_t *area, uint8_t *color_map) { display_driver->flush(disp, area, color_map); }, .rotation_callback = [display_driver](const espp::DisplayRotation &rotation) { display_driver->set_rotation(rotation); }, .rotation = rotation}, #if DISPLAY_IS_OLED Display::OledConfig{ .set_brightness_callback = [display_driver](float brightness) { display_driver->set_brightness(brightness); }, .get_brightness_callback = [display_driver]() { return display_driver->get_brightness(); }}, #else Display::LcdConfig{.backlight_pin = backlight, .backlight_on_value = backlight_on_value}, #endif Display::DynamicMemoryConfig{.pixel_buffer_size = pixel_buffer_size, .double_buffered = true}); display->set_brightness(1.0f); // initialize the gui Gui gui({}); size_t iterations = 0; while (true) { auto label = fmt::format("Iterations: {}", iterations); gui.set_label(label); gui.set_meter(iterations % 100); iterations++; std::this_thread::sleep_for(100ms); }
Public Functions
-
inline virtual bool initialize() override
Initialize the concrete display controller.
- Returns:
True on success.
-
inline virtual void set_rotation(const DisplayRotation &rotation) override
Update the controller rotation state.
- Parameters:
rotation – New display rotation.
-
inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override
Clear a rectangular region to a solid color.
- Parameters:
x – Starting X coordinate.
y – Starting Y coordinate.
width – Width in pixels.
height – Height in pixels.
color – RGB565 color value.
-
inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
Write an area of pixel data without implicitly notifying LVGL.
- Parameters:
disp – LVGL display pointer, used when synchronous flush completion is needed.
area – Area to update.
color_map – Pixel buffer for the area.
flags – Transport/user flags passed through to the write path.
-
inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
Flush an area of pixel data and notify LVGL when appropriate.
- Parameters:
disp – LVGL display pointer.
area – Area to flush.
color_map – Pixel buffer for the area.
-
inline virtual void set_offset(int x, int y)
Update the controller’s logical top-left pixel offset.
- Parameters:
x – X offset in pixels.
y – Y offset in pixels.
-
inline virtual void get_offset(int &x, int &y) const
Read the controller’s logical top-left pixel offset.
- Parameters:
x – Filled with the current X offset.
y – Filled with the current Y offset.
-
inline virtual bool initialize() override
Header File
Classes
-
class Ili9341 : public espp::display_drivers::MipiDbiDisplayDriver
Display driver for the ILI9341 display controller.
WROVER-KIT ILI9341 Config
static constexpr std::string_view dev_kit = "ESP-WROVER-DevKit"; int clock_speed = 20 * 1000 * 1000; gpio_num_t mosi = GPIO_NUM_23; gpio_num_t sclk = GPIO_NUM_19; gpio_num_t spics = GPIO_NUM_22; gpio_num_t reset = GPIO_NUM_18; gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM; gpio_num_t backlight = GPIO_NUM_5; size_t width = 320; size_t height = 240; size_t pixel_buffer_size = 16384; bool backlight_on_value = false; bool reset_value = false; bool invert_colors = false; int offset_x = 0; int offset_y = 0; bool mirror_x = false; bool mirror_y = false; auto rotation = espp::DisplayRotation::LANDSCAPE;
ili9341 Example
spi_bus = std::make_unique<espp::Spi>(espp::Spi::Config{ .host = spi_num, .sclk_io_num = sclk, .mosi_io_num = mosi, #ifdef CONFIG_DISPLAY_QUAD_SPI .miso_io_num = miso, .quadwp_io_num = data2, .quadhd_io_num = data3, #else .miso_io_num = GPIO_NUM_NC, #endif .max_transfer_sz = SPI_MAX_TRANSFER_BYTES, }); if (!spi_bus->initialized()) { fmt::print("Failed to initialize SPI bus\n"); return; } #ifdef CONFIG_DISPLAY_QUAD_SPI std::error_code ec; spi_device = spi_bus->add_device( espp::Spi::DeviceConfig{ .command_bits = 8, .address_bits = 24, .mode = 0, .clock_speed_hz = clock_speed, .input_delay_ns = 0, .cs_io_num = spics, .queue_size = spi_queue_size, .flags = SPI_DEVICE_HALFDUPLEX, #ifndef CONFIG_T_ENCODER_PRO .pre_cb = lcd_spi_pre_transfer_callback, #endif .post_cb = lcd_spi_post_transfer_callback, }, ec); if (ec || !spi_device) { fmt::print("Failed to initialize SPI device: {}\n", ec.message()); return; } #else panel_io = std::make_unique<espp::SpiPanelIo>(espp::SpiPanelIo::Config{ .spi = spi_bus.get(), .device_config = { .mode = 0, .clock_speed_hz = clock_speed, .input_delay_ns = 0, .cs_io_num = spics, .queue_size = spi_queue_size, #ifdef CONFIG_HARDWARE_BYTE90 .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_3WIRE, #endif }, .data_command_io = dc_pin, .data_command_bit_mask = DC_LEVEL_BIT, .post_transaction_callback_bit_mask = FLUSH_BIT, .post_transaction_callback = lcd_spi_flush_ready, }); if (!panel_io->initialized()) { fmt::print("Failed to initialize SPI panel I/O\n"); return; } #endif auto display_driver = std::make_shared<DisplayDriver>(espp::display_drivers::Config{ .panel_io = #ifdef CONFIG_DISPLAY_QUAD_SPI nullptr, .write_command = write_command, #else panel_io.get(), .write_command = nullptr, #endif .read_command = nullptr, #ifdef CONFIG_DISPLAY_QUAD_SPI .lcd_send_lines = lcd_send_lines, #else .lcd_send_lines = nullptr, #endif .reset_pin = reset, #ifndef CONFIG_T_ENCODER_PRO .data_command_pin = dc_pin, #endif .reset_value = reset_value, .invert_colors = invert_colors, .offset_x = offset_x, .offset_y = offset_y, .mirror_x = mirror_x, .mirror_y = mirror_y, }); display_driver->initialize(); // initialize the display / lvgl auto display = std::make_shared<Display>( Display::LvglConfig{ .width = width, .height = height, .flush_callback = [display_driver](lv_display_t *disp, const lv_area_t *area, uint8_t *color_map) { display_driver->flush(disp, area, color_map); }, .rotation_callback = [display_driver](const espp::DisplayRotation &rotation) { display_driver->set_rotation(rotation); }, .rotation = rotation}, #if DISPLAY_IS_OLED Display::OledConfig{ .set_brightness_callback = [display_driver](float brightness) { display_driver->set_brightness(brightness); }, .get_brightness_callback = [display_driver]() { return display_driver->get_brightness(); }}, #else Display::LcdConfig{.backlight_pin = backlight, .backlight_on_value = backlight_on_value}, #endif Display::DynamicMemoryConfig{.pixel_buffer_size = pixel_buffer_size, .double_buffered = true}); display->set_brightness(1.0f); // initialize the gui Gui gui({}); size_t iterations = 0; while (true) { auto label = fmt::format("Iterations: {}", iterations); gui.set_label(label); gui.set_meter(iterations % 100); iterations++; std::this_thread::sleep_for(100ms); }
Public Functions
-
inline virtual bool initialize() override
Initialize the concrete display controller.
- Returns:
True on success.
-
inline virtual void set_rotation(const DisplayRotation &rotation) override
Update the controller rotation state.
- Parameters:
rotation – New display rotation.
-
inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override
Clear a rectangular region to a solid color.
- Parameters:
x – Starting X coordinate.
y – Starting Y coordinate.
width – Width in pixels.
height – Height in pixels.
color – RGB565 color value.
-
inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
Write an area of pixel data without implicitly notifying LVGL.
- Parameters:
disp – LVGL display pointer, used when synchronous flush completion is needed.
area – Area to update.
color_map – Pixel buffer for the area.
flags – Transport/user flags passed through to the write path.
-
inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
Flush an area of pixel data and notify LVGL when appropriate.
- Parameters:
disp – LVGL display pointer.
area – Area to flush.
color_map – Pixel buffer for the area.
-
inline virtual void set_offset(int x, int y)
Update the controller’s logical top-left pixel offset.
- Parameters:
x – X offset in pixels.
y – Y offset in pixels.
-
inline virtual void get_offset(int &x, int &y) const
Read the controller’s logical top-left pixel offset.
- Parameters:
x – Filled with the current X offset.
y – Filled with the current Y offset.
-
inline virtual bool initialize() override
Header File
Classes
-
class Ili9881 : public espp::display_drivers::MipiDbiDisplayDriver
Display driver for the ILI9881C display controller (DSI/DCS style).
This follows the same interface as the other display drivers and relies on a lower-level transport to execute write_command and bulk color transfers.
The initialization sequence includes the comprehensive M5Stack Tab5 setup with GIP (Gate In Panel) timing control, power management, and gamma correction for optimal display quality.
Public Functions
-
inline virtual bool initialize() override
Initialize the concrete display controller.
- Returns:
True on success.
-
inline virtual void set_rotation(const DisplayRotation &rotation) override
Update the controller rotation state.
- Parameters:
rotation – New display rotation.
-
inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override
Clear a rectangular region to a solid color.
- Parameters:
x – Starting X coordinate.
y – Starting Y coordinate.
width – Width in pixels.
height – Height in pixels.
color – RGB565 color value.
-
inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
Write an area of pixel data without implicitly notifying LVGL.
- Parameters:
disp – LVGL display pointer, used when synchronous flush completion is needed.
area – Area to update.
color_map – Pixel buffer for the area.
flags – Transport/user flags passed through to the write path.
-
inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
Flush an area of pixel data and notify LVGL when appropriate.
- Parameters:
disp – LVGL display pointer.
area – Area to flush.
color_map – Pixel buffer for the area.
-
inline virtual void set_offset(int x, int y)
Update the controller’s logical top-left pixel offset.
- Parameters:
x – X offset in pixels.
y – Y offset in pixels.
-
inline virtual void get_offset(int &x, int &y) const
Read the controller’s logical top-left pixel offset.
- Parameters:
x – Filled with the current X offset.
y – Filled with the current Y offset.
-
inline virtual bool initialize() override
Header File
Classes
-
class Sh8601 : public espp::display_drivers::MipiDbiDisplayDriver
Display driver for the SH8601 display controller.
SmartKnob Config
static constexpr std::string_view dev_kit = "Lilygo T-Encoder-Pro"; int clock_speed = 80 * 1000 * 1000; constexpr gpio_num_t mosi = GPIO_NUM_11; constexpr gpio_num_t miso = GPIO_NUM_13; constexpr gpio_num_t data2 = GPIO_NUM_7; constexpr gpio_num_t data3 = GPIO_NUM_14; constexpr gpio_num_t sclk = GPIO_NUM_12; constexpr gpio_num_t spics = GPIO_NUM_10; constexpr gpio_num_t reset = GPIO_NUM_4; constexpr gpio_num_t enable = GPIO_NUM_3; constexpr size_t width = 390; constexpr size_t height = 390; constexpr size_t pixel_buffer_size = width * height / 10; bool reset_value = false; bool invert_colors = false; int offset_x = 0; int offset_y = 0; bool mirror_x = false; bool mirror_y = false; auto rotation = espp::DisplayRotation::LANDSCAPE;
Sh8601 Example
spi_bus = std::make_unique<espp::Spi>(espp::Spi::Config{ .host = spi_num, .sclk_io_num = sclk, .mosi_io_num = mosi, #ifdef CONFIG_DISPLAY_QUAD_SPI .miso_io_num = miso, .quadwp_io_num = data2, .quadhd_io_num = data3, #else .miso_io_num = GPIO_NUM_NC, #endif .max_transfer_sz = SPI_MAX_TRANSFER_BYTES, }); if (!spi_bus->initialized()) { fmt::print("Failed to initialize SPI bus\n"); return; } #ifdef CONFIG_DISPLAY_QUAD_SPI std::error_code ec; spi_device = spi_bus->add_device( espp::Spi::DeviceConfig{ .command_bits = 8, .address_bits = 24, .mode = 0, .clock_speed_hz = clock_speed, .input_delay_ns = 0, .cs_io_num = spics, .queue_size = spi_queue_size, .flags = SPI_DEVICE_HALFDUPLEX, #ifndef CONFIG_T_ENCODER_PRO .pre_cb = lcd_spi_pre_transfer_callback, #endif .post_cb = lcd_spi_post_transfer_callback, }, ec); if (ec || !spi_device) { fmt::print("Failed to initialize SPI device: {}\n", ec.message()); return; } #else panel_io = std::make_unique<espp::SpiPanelIo>(espp::SpiPanelIo::Config{ .spi = spi_bus.get(), .device_config = { .mode = 0, .clock_speed_hz = clock_speed, .input_delay_ns = 0, .cs_io_num = spics, .queue_size = spi_queue_size, #ifdef CONFIG_HARDWARE_BYTE90 .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_3WIRE, #endif }, .data_command_io = dc_pin, .data_command_bit_mask = DC_LEVEL_BIT, .post_transaction_callback_bit_mask = FLUSH_BIT, .post_transaction_callback = lcd_spi_flush_ready, }); if (!panel_io->initialized()) { fmt::print("Failed to initialize SPI panel I/O\n"); return; } #endif auto display_driver = std::make_shared<DisplayDriver>(espp::display_drivers::Config{ .panel_io = #ifdef CONFIG_DISPLAY_QUAD_SPI nullptr, .write_command = write_command, #else panel_io.get(), .write_command = nullptr, #endif .read_command = nullptr, #ifdef CONFIG_DISPLAY_QUAD_SPI .lcd_send_lines = lcd_send_lines, #else .lcd_send_lines = nullptr, #endif .reset_pin = reset, #ifndef CONFIG_T_ENCODER_PRO .data_command_pin = dc_pin, #endif .reset_value = reset_value, .invert_colors = invert_colors, .offset_x = offset_x, .offset_y = offset_y, .mirror_x = mirror_x, .mirror_y = mirror_y, }); display_driver->initialize(); // initialize the display / lvgl auto display = std::make_shared<Display>( Display::LvglConfig{ .width = width, .height = height, .flush_callback = [display_driver](lv_display_t *disp, const lv_area_t *area, uint8_t *color_map) { display_driver->flush(disp, area, color_map); }, .rotation_callback = [display_driver](const espp::DisplayRotation &rotation) { display_driver->set_rotation(rotation); }, .rotation = rotation}, #if DISPLAY_IS_OLED Display::OledConfig{ .set_brightness_callback = [display_driver](float brightness) { display_driver->set_brightness(brightness); }, .get_brightness_callback = [display_driver]() { return display_driver->get_brightness(); }}, #else Display::LcdConfig{.backlight_pin = backlight, .backlight_on_value = backlight_on_value}, #endif Display::DynamicMemoryConfig{.pixel_buffer_size = pixel_buffer_size, .double_buffered = true}); display->set_brightness(1.0f); // initialize the gui Gui gui({}); size_t iterations = 0; while (true) { auto label = fmt::format("Iterations: {}", iterations); gui.set_label(label); gui.set_meter(iterations % 100); iterations++; std::this_thread::sleep_for(100ms); }
Public Functions
-
inline virtual bool initialize() override
Initialize the concrete display controller.
- Returns:
True on success.
-
inline virtual void set_rotation(const DisplayRotation &rotation) override
Update the controller rotation state.
- Parameters:
rotation – New display rotation.
-
inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override
Clear a rectangular region to a solid color.
- Parameters:
x – Starting X coordinate.
y – Starting Y coordinate.
width – Width in pixels.
height – Height in pixels.
color – RGB565 color value.
-
inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
Write an area of pixel data without implicitly notifying LVGL.
- Parameters:
disp – LVGL display pointer, used when synchronous flush completion is needed.
area – Area to update.
color_map – Pixel buffer for the area.
flags – Transport/user flags passed through to the write path.
-
inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
Flush an area of pixel data and notify LVGL when appropriate.
- Parameters:
disp – LVGL display pointer.
area – Area to flush.
color_map – Pixel buffer for the area.
-
inline virtual void set_offset(int x, int y)
Update the controller’s logical top-left pixel offset.
- Parameters:
x – X offset in pixels.
y – Y offset in pixels.
-
inline virtual void get_offset(int &x, int &y) const
Read the controller’s logical top-left pixel offset.
- Parameters:
x – Filled with the current X offset.
y – Filled with the current Y offset.
-
inline virtual bool initialize() override
Header File
Classes
-
class SpiPanelIo : public espp::display_drivers::PanelIo, public espp::BaseComponent
LCD-style command/data helper built on top of `Spi`.
`queue_command()` transmits with D/C low. `queue_data()` and `queue_pixels()` always transmit with D/C high, so callers should treat them as payload helpers rather than manually setting the D/C bit for normal panel data transactions.
Public Types
-
using post_transaction_callback_t = void (*)(uint32_t user_flags)
IRQ-safe callback invoked after matching queued transactions finish.
Public Functions
-
explicit SpiPanelIo(const Config &config)
Construct a panel-I/O helper for SPI command/data displays.
- Parameters:
config – Panel transport configuration.
-
virtual bool initialized() const override
Check whether the helper has a registered SPI device.
- Returns:
True if initialization succeeded.
-
std::shared_ptr<Spi::Device> device() const
Get the underlying SPI device wrapper.
- Returns:
Shared pointer to the attached SPI device.
-
virtual void wait() override
Wait for all queued transactions to complete.
-
virtual void write_command(uint8_t command, std::span<const uint8_t> parameters, uint32_t user_flags = 0) override
Send a command byte and optional parameter payload.
- Parameters:
command – Command byte sent with D/C low.
parameters – Optional payload bytes sent with D/C high.
user_flags – Additional user-defined flags passed to callbacks.
-
virtual void queue_command(uint8_t command, uint32_t user_flags = 0) override
Queue a command transaction with D/C low.
- Parameters:
command – Command byte to transmit.
user_flags – Additional user-defined flags passed to callbacks.
-
virtual void queue_data(std::span<const uint8_t> data, uint32_t user_flags = 0) override
Queue a non-pixel data payload with D/C high.
- Parameters:
data – Data bytes to transmit.
user_flags – Additional user-defined flags passed to callbacks.
-
virtual void queue_pixels(const uint8_t *data, size_t size, uint32_t user_flags = 0, uint32_t transaction_flags = 0) override
Queue a pixel payload with D/C high.
- Parameters:
data – Pointer to the pixel buffer.
size – Pixel payload size in bytes.
user_flags – Additional user-defined flags passed to callbacks.
transaction_flags – Optional SPI transaction flags overriding the default pixel flags.
-
inline const std::string &get_name() const
Get the name of the component
Note
This is the tag of the logger
- Returns:
A const reference to the name of the component
-
inline void set_log_tag(const std::string_view &tag)
Set the tag for the logger
- Parameters:
tag – The tag to use for the logger
-
inline espp::Logger::Verbosity get_log_level() const
Get the log level for the logger
See also
See also
- Returns:
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- Parameters:
level – The verbosity level to use for the logger
-
inline void set_log_verbosity(espp::Logger::Verbosity level)
Set the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls set_log_level
- Parameters:
level – The verbosity level to use for the logger
-
inline espp::Logger::Verbosity get_log_verbosity() const
Get the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls get_log_level
- Returns:
The verbosity level of the logger
-
inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
Set the rate limit for the logger
See also
Note
Only calls to the logger that have _rate_limit suffix will be rate limited
- Parameters:
rate_limit – The rate limit to use for the logger
-
struct Config
Configuration for `SpiPanelIo`.
Public Members
-
Spi::DeviceConfig device_config = {}
SPI device configuration.
-
gpio_num_t data_command_io = GPIO_NUM_NC
D/C GPIO pin.
-
uint32_t data_command_bit_mask = 1u << static_cast<uint32_t>(display_drivers::Flags::DC_LEVEL_BIT)
User bit that selects data mode.
-
uint32_t post_transaction_callback_bit_mask = 0
User bit mask that triggers the callback.
-
post_transaction_callback_t post_transaction_callback = nullptr
Optional IRQ-safe callback.
-
uint32_t pixel_data_flags = SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL
Flags used for pixel payload transfers.
-
uint32_t timeout_ms = 10
Queue/result timeout in milliseconds.
-
Spi::DeviceConfig device_config = {}
-
using post_transaction_callback_t = void (*)(uint32_t user_flags)
Header File
Classes
-
class Ssd1351 : public espp::display_drivers::MipiDbiDisplayDriver
Display driver for the SSD1351 128x128 RGB OLED display controller.
Byte90 Ssd1351 Config
static constexpr std::string_view dev_kit = "ALXV Labs Byte90"; int clock_speed = 20 * 1000 * 1000; constexpr gpio_num_t mosi = GPIO_NUM_9; constexpr gpio_num_t miso = GPIO_NUM_NC; constexpr gpio_num_t sclk = GPIO_NUM_7; constexpr gpio_num_t spics = GPIO_NUM_44; constexpr gpio_num_t reset = GPIO_NUM_1; constexpr gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM; constexpr size_t width = 128; constexpr size_t height = 128; constexpr size_t pixel_buffer_size = width * height * sizeof(uint16_t); bool reset_value = false; bool invert_colors = false; int offset_x = 0; int offset_y = 0; bool mirror_x = false; bool mirror_y = true; auto rotation = espp::DisplayRotation::LANDSCAPE;
ssd1351 Example
spi_bus = std::make_unique<espp::Spi>(espp::Spi::Config{ .host = spi_num, .sclk_io_num = sclk, .mosi_io_num = mosi, #ifdef CONFIG_DISPLAY_QUAD_SPI .miso_io_num = miso, .quadwp_io_num = data2, .quadhd_io_num = data3, #else .miso_io_num = GPIO_NUM_NC, #endif .max_transfer_sz = SPI_MAX_TRANSFER_BYTES, }); if (!spi_bus->initialized()) { fmt::print("Failed to initialize SPI bus\n"); return; } #ifdef CONFIG_DISPLAY_QUAD_SPI std::error_code ec; spi_device = spi_bus->add_device( espp::Spi::DeviceConfig{ .command_bits = 8, .address_bits = 24, .mode = 0, .clock_speed_hz = clock_speed, .input_delay_ns = 0, .cs_io_num = spics, .queue_size = spi_queue_size, .flags = SPI_DEVICE_HALFDUPLEX, #ifndef CONFIG_T_ENCODER_PRO .pre_cb = lcd_spi_pre_transfer_callback, #endif .post_cb = lcd_spi_post_transfer_callback, }, ec); if (ec || !spi_device) { fmt::print("Failed to initialize SPI device: {}\n", ec.message()); return; } #else panel_io = std::make_unique<espp::SpiPanelIo>(espp::SpiPanelIo::Config{ .spi = spi_bus.get(), .device_config = { .mode = 0, .clock_speed_hz = clock_speed, .input_delay_ns = 0, .cs_io_num = spics, .queue_size = spi_queue_size, #ifdef CONFIG_HARDWARE_BYTE90 .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_3WIRE, #endif }, .data_command_io = dc_pin, .data_command_bit_mask = DC_LEVEL_BIT, .post_transaction_callback_bit_mask = FLUSH_BIT, .post_transaction_callback = lcd_spi_flush_ready, }); if (!panel_io->initialized()) { fmt::print("Failed to initialize SPI panel I/O\n"); return; } #endif auto display_driver = std::make_shared<DisplayDriver>(espp::display_drivers::Config{ .panel_io = #ifdef CONFIG_DISPLAY_QUAD_SPI nullptr, .write_command = write_command, #else panel_io.get(), .write_command = nullptr, #endif .read_command = nullptr, #ifdef CONFIG_DISPLAY_QUAD_SPI .lcd_send_lines = lcd_send_lines, #else .lcd_send_lines = nullptr, #endif .reset_pin = reset, #ifndef CONFIG_T_ENCODER_PRO .data_command_pin = dc_pin, #endif .reset_value = reset_value, .invert_colors = invert_colors, .offset_x = offset_x, .offset_y = offset_y, .mirror_x = mirror_x, .mirror_y = mirror_y, }); display_driver->initialize(); // initialize the display / lvgl auto display = std::make_shared<Display>( Display::LvglConfig{ .width = width, .height = height, .flush_callback = [display_driver](lv_display_t *disp, const lv_area_t *area, uint8_t *color_map) { display_driver->flush(disp, area, color_map); }, .rotation_callback = [display_driver](const espp::DisplayRotation &rotation) { display_driver->set_rotation(rotation); }, .rotation = rotation}, #if DISPLAY_IS_OLED Display::OledConfig{ .set_brightness_callback = [display_driver](float brightness) { display_driver->set_brightness(brightness); }, .get_brightness_callback = [display_driver]() { return display_driver->get_brightness(); }}, #else Display::LcdConfig{.backlight_pin = backlight, .backlight_on_value = backlight_on_value}, #endif Display::DynamicMemoryConfig{.pixel_buffer_size = pixel_buffer_size, .double_buffered = true}); display->set_brightness(1.0f); // initialize the gui Gui gui({}); size_t iterations = 0; while (true) { auto label = fmt::format("Iterations: {}", iterations); gui.set_label(label); gui.set_meter(iterations % 100); iterations++; std::this_thread::sleep_for(100ms); }
Public Functions
-
inline virtual bool initialize() override
Initialize the concrete display controller.
- Returns:
True on success.
-
inline virtual void set_rotation(const DisplayRotation &rotation) override
Update the controller rotation state.
- Parameters:
rotation – New display rotation.
-
inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override
Clear a rectangular region to a solid color.
- Parameters:
x – Starting X coordinate.
y – Starting Y coordinate.
width – Width in pixels.
height – Height in pixels.
color – RGB565 color value.
-
inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
Write an area of pixel data without implicitly notifying LVGL.
- Parameters:
disp – LVGL display pointer, used when synchronous flush completion is needed.
area – Area to update.
color_map – Pixel buffer for the area.
flags – Transport/user flags passed through to the write path.
-
inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
Flush an area of pixel data and notify LVGL when appropriate.
- Parameters:
disp – LVGL display pointer.
area – Area to flush.
color_map – Pixel buffer for the area.
-
inline virtual void set_offset(int x, int y)
Update the controller’s logical top-left pixel offset.
- Parameters:
x – X offset in pixels.
y – Y offset in pixels.
-
inline virtual void get_offset(int &x, int &y) const
Read the controller’s logical top-left pixel offset.
- Parameters:
x – Filled with the current X offset.
y – Filled with the current Y offset.
-
inline virtual bool initialize() override
Header File
Classes
-
class St7123 : public espp::display_drivers::MipiDbiDisplayDriver
Public Functions
-
inline virtual bool initialize() override
Initialize the concrete display controller.
- Returns:
True on success.
-
inline virtual void set_rotation(const DisplayRotation &rotation) override
Update the controller rotation state.
- Parameters:
rotation – New display rotation.
-
inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override
Clear a rectangular region to a solid color.
- Parameters:
x – Starting X coordinate.
y – Starting Y coordinate.
width – Width in pixels.
height – Height in pixels.
color – RGB565 color value.
-
inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
Write an area of pixel data without implicitly notifying LVGL.
- Parameters:
disp – LVGL display pointer, used when synchronous flush completion is needed.
area – Area to update.
color_map – Pixel buffer for the area.
flags – Transport/user flags passed through to the write path.
-
inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
Flush an area of pixel data and notify LVGL when appropriate.
- Parameters:
disp – LVGL display pointer.
area – Area to flush.
color_map – Pixel buffer for the area.
-
inline virtual void set_offset(int x, int y)
Update the controller’s logical top-left pixel offset.
- Parameters:
x – X offset in pixels.
y – Y offset in pixels.
-
inline virtual void get_offset(int &x, int &y) const
Read the controller’s logical top-left pixel offset.
- Parameters:
x – Filled with the current X offset.
y – Filled with the current Y offset.
-
inline virtual bool initialize() override
Header File
Classes
-
class St7789 : public espp::display_drivers::MipiDbiDisplayDriver
Display driver for the ST7789 display controller.
This code is modified from https://github.com/lvgl/lvgl_esp32_drivers/blob/master/lvgl_tft/st7789.c and https://github.com/Bodmer/TFT_eSPI/blob/master/TFT_Drivers/ST7789_Defines.h
TTGO St7789 Config
static constexpr std::string_view dev_kit = "TTGO T-Display"; int clock_speed = 60 * 1000 * 1000; gpio_num_t mosi = GPIO_NUM_19; gpio_num_t sclk = GPIO_NUM_18; gpio_num_t spics = GPIO_NUM_5; gpio_num_t reset = GPIO_NUM_23; gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM; gpio_num_t backlight = GPIO_NUM_4; size_t width = 240; size_t height = 135; size_t pixel_buffer_size = 12800; bool backlight_on_value = false; bool reset_value = false; bool invert_colors = false; int offset_x = 40; int offset_y = 53; bool mirror_x = false; bool mirror_y = false; auto rotation = espp::DisplayRotation::PORTRAIT;
ESP32-S3-BOX St7789 Config
static constexpr std::string_view dev_kit = "ESP32-S3-BOX"; int clock_speed = 60 * 1000 * 1000; gpio_num_t mosi = GPIO_NUM_6; gpio_num_t sclk = GPIO_NUM_7; gpio_num_t spics = GPIO_NUM_5; gpio_num_t reset = GPIO_NUM_48; gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM; gpio_num_t backlight = GPIO_NUM_45; size_t width = 320; size_t height = 240; size_t pixel_buffer_size = width * 50; bool backlight_on_value = true; bool reset_value = false; bool invert_colors = true; int offset_x = 0; int offset_y = 0; bool mirror_x = true; bool mirror_y = true; auto rotation = espp::DisplayRotation::LANDSCAPE;
st7789 Example
spi_bus = std::make_unique<espp::Spi>(espp::Spi::Config{ .host = spi_num, .sclk_io_num = sclk, .mosi_io_num = mosi, #ifdef CONFIG_DISPLAY_QUAD_SPI .miso_io_num = miso, .quadwp_io_num = data2, .quadhd_io_num = data3, #else .miso_io_num = GPIO_NUM_NC, #endif .max_transfer_sz = SPI_MAX_TRANSFER_BYTES, }); if (!spi_bus->initialized()) { fmt::print("Failed to initialize SPI bus\n"); return; } #ifdef CONFIG_DISPLAY_QUAD_SPI std::error_code ec; spi_device = spi_bus->add_device( espp::Spi::DeviceConfig{ .command_bits = 8, .address_bits = 24, .mode = 0, .clock_speed_hz = clock_speed, .input_delay_ns = 0, .cs_io_num = spics, .queue_size = spi_queue_size, .flags = SPI_DEVICE_HALFDUPLEX, #ifndef CONFIG_T_ENCODER_PRO .pre_cb = lcd_spi_pre_transfer_callback, #endif .post_cb = lcd_spi_post_transfer_callback, }, ec); if (ec || !spi_device) { fmt::print("Failed to initialize SPI device: {}\n", ec.message()); return; } #else panel_io = std::make_unique<espp::SpiPanelIo>(espp::SpiPanelIo::Config{ .spi = spi_bus.get(), .device_config = { .mode = 0, .clock_speed_hz = clock_speed, .input_delay_ns = 0, .cs_io_num = spics, .queue_size = spi_queue_size, #ifdef CONFIG_HARDWARE_BYTE90 .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_3WIRE, #endif }, .data_command_io = dc_pin, .data_command_bit_mask = DC_LEVEL_BIT, .post_transaction_callback_bit_mask = FLUSH_BIT, .post_transaction_callback = lcd_spi_flush_ready, }); if (!panel_io->initialized()) { fmt::print("Failed to initialize SPI panel I/O\n"); return; } #endif auto display_driver = std::make_shared<DisplayDriver>(espp::display_drivers::Config{ .panel_io = #ifdef CONFIG_DISPLAY_QUAD_SPI nullptr, .write_command = write_command, #else panel_io.get(), .write_command = nullptr, #endif .read_command = nullptr, #ifdef CONFIG_DISPLAY_QUAD_SPI .lcd_send_lines = lcd_send_lines, #else .lcd_send_lines = nullptr, #endif .reset_pin = reset, #ifndef CONFIG_T_ENCODER_PRO .data_command_pin = dc_pin, #endif .reset_value = reset_value, .invert_colors = invert_colors, .offset_x = offset_x, .offset_y = offset_y, .mirror_x = mirror_x, .mirror_y = mirror_y, }); display_driver->initialize(); // initialize the display / lvgl auto display = std::make_shared<Display>( Display::LvglConfig{ .width = width, .height = height, .flush_callback = [display_driver](lv_display_t *disp, const lv_area_t *area, uint8_t *color_map) { display_driver->flush(disp, area, color_map); }, .rotation_callback = [display_driver](const espp::DisplayRotation &rotation) { display_driver->set_rotation(rotation); }, .rotation = rotation}, #if DISPLAY_IS_OLED Display::OledConfig{ .set_brightness_callback = [display_driver](float brightness) { display_driver->set_brightness(brightness); }, .get_brightness_callback = [display_driver]() { return display_driver->get_brightness(); }}, #else Display::LcdConfig{.backlight_pin = backlight, .backlight_on_value = backlight_on_value}, #endif Display::DynamicMemoryConfig{.pixel_buffer_size = pixel_buffer_size, .double_buffered = true}); display->set_brightness(1.0f); // initialize the gui Gui gui({}); size_t iterations = 0; while (true) { auto label = fmt::format("Iterations: {}", iterations); gui.set_label(label); gui.set_meter(iterations % 100); iterations++; std::this_thread::sleep_for(100ms); }
Public Functions
-
inline virtual bool initialize() override
Initialize the concrete display controller.
- Returns:
True on success.
-
inline virtual void set_rotation(const DisplayRotation &rotation) override
Update the controller rotation state.
- Parameters:
rotation – New display rotation.
-
inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override
Clear a rectangular region to a solid color.
- Parameters:
x – Starting X coordinate.
y – Starting Y coordinate.
width – Width in pixels.
height – Height in pixels.
color – RGB565 color value.
-
inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
Write an area of pixel data without implicitly notifying LVGL.
- Parameters:
disp – LVGL display pointer, used when synchronous flush completion is needed.
area – Area to update.
color_map – Pixel buffer for the area.
flags – Transport/user flags passed through to the write path.
-
inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
Flush an area of pixel data and notify LVGL when appropriate.
- Parameters:
disp – LVGL display pointer.
area – Area to flush.
color_map – Pixel buffer for the area.
-
inline virtual void set_offset(int x, int y)
Update the controller’s logical top-left pixel offset.
- Parameters:
x – X offset in pixels.
y – Y offset in pixels.
-
inline virtual void get_offset(int &x, int &y) const
Read the controller’s logical top-left pixel offset.
- Parameters:
x – Filled with the current X offset.
y – Filled with the current Y offset.
-
inline virtual bool initialize() override
Header File
Classes
-
class St7796 : public espp::display_drivers::MipiDbiDisplayDriver
Display driver for the ST7796 display controller.
Public Types
-
enum class Command : uint8_t
Supported command values used by this driver wrapper.
Values:
-
enumerator slpout
Exit sleep mode.
-
enumerator invoff
Disable display inversion.
-
enumerator invon
Enable display inversion.
-
enumerator dispon
Turn the display on.
-
enumerator caset
Set the column address window.
-
enumerator raset
Set the row address window.
-
enumerator ramwr
Write pixel data to RAM.
-
enumerator madctl
Configure memory addressing and rotation.
-
enumerator colmod
Configure color depth / pixel format.
-
enumerator slpout
Public Functions
-
inline virtual bool initialize() override
Initialize the concrete display controller.
- Returns:
True on success.
-
inline virtual void set_rotation(const DisplayRotation &rotation) override
Update the controller rotation state.
- Parameters:
rotation – New display rotation.
-
inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override
Clear a rectangular region to a solid color.
- Parameters:
x – Starting X coordinate.
y – Starting Y coordinate.
width – Width in pixels.
height – Height in pixels.
color – RGB565 color value.
-
inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)
Write an area of pixel data without implicitly notifying LVGL.
- Parameters:
disp – LVGL display pointer, used when synchronous flush completion is needed.
area – Area to update.
color_map – Pixel buffer for the area.
flags – Transport/user flags passed through to the write path.
-
inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)
Flush an area of pixel data and notify LVGL when appropriate.
- Parameters:
disp – LVGL display pointer.
area – Area to flush.
color_map – Pixel buffer for the area.
-
inline virtual void set_offset(int x, int y)
Update the controller’s logical top-left pixel offset.
- Parameters:
x – X offset in pixels.
y – Y offset in pixels.
-
inline virtual void get_offset(int &x, int &y) const
Read the controller’s logical top-left pixel offset.
- Parameters:
x – Filled with the current X offset.
y – Filled with the current Y offset.
-
enum class Command : uint8_t