#ifndef PANEL_DEVICE_H #define PANEL_DEVICE_H #include #include #include #include #include #include "i2c.h" // LVGL reserves 2x4 bytes in the buffer to be used as a palette. // This additional space must be added to the IPanelDevice::buf_size_. #define LVGL_PALETTE_SIZE 8 /** * Encapsulates vendor specific ESP LCD pabel initialization logic. * This pure virtual interface can be inherited from for using new LCD devices. * See the SSD1306 example for implementing a PanelDevice for NT35510 or ST7789. * * At this time only I2C is supported. * Classes that inherit from this interface should likely be marked final. */ class IPanelDevice { public: /** * Construct an IPanelDevice. * * @param i2c I2C object. Eventually this will mature to IProtocol or similar. * @param config I2C configuration for this device. * @param height Height of the device screen in pixels. * @param width Width of the device screen in pixels. */ explicit IPanelDevice(I2C &i2c, esp_lcd_panel_io_i2c_config_t config, int width, int height) : IPanelDevice(i2c, config, width, height, width * height / 8 + LVGL_PALETTE_SIZE) { } /** * Construct an IPanelDevice. * * @param i2c I2C object. Eventually this will mature to IProtocol or similar. * @param config I2C configuration for this device. * @param height Height of the device screen in pixels. * @param width Width of the device screen in pixels. * @param draw_buf_size Size of the draw buffer for this device. */ explicit IPanelDevice(I2C &i2c, esp_lcd_panel_io_i2c_config_t io_config, int width, int height, size_t draw_buf_size) : width_(width), height_(height), rst_num_(i2c.rst_num_), lv_buf_size_(draw_buf_size), esp_io_config_(io_config) { } virtual ~IPanelDevice() = default; /** * Create an LVGL display using the width and height of this device. * * @return Handle to the created LVGL display. */ [[nodiscard]] lv_display_t *create_display() const { auto display = lv_display_create(width_, height_); assert(display); return display; } /** * Create an ESP LCD panel IO handle. * * @return The created ESP LCD panel IO handle. */ [[nodiscard]] esp_lcd_panel_io_handle_t create_io_handle() { ESP_LOGI(TAG, "Creating panel IO handle"); esp_lcd_panel_io_handle_t handle = nullptr; ESP_ERROR_CHECK( esp_lcd_new_panel_io_i2c(I2C::get(), &esp_io_config_, &handle)); return handle; } /** * Create and initialize an ESP panel handle. * IPanelDevice implementors must initialize the panel within init_panel. * * @param config ESP LCD panel configuration. * @param io ESP LCD panel IO handle. * @param [out] panel ESP LCD panel handle output pointer location. */ void create_panel(esp_lcd_panel_dev_config_t &config, esp_lcd_panel_io_handle_t io, esp_lcd_panel_handle_t &panel) { // If the passed handle is already allocated, delete it. if (panel != nullptr) { ESP_LOGI(TAG, "Removing unused panel"); esp_lcd_panel_del(panel); } ESP_LOGI(TAG, "Install SSD1306 panel driver"); // Call pure virtual method responsible for initializing the panel handle. init_panel(config, io, panel); } /** * Retrieve the device specific vendor configuration structure. * * @return Address of vendor configuration structure. * @sa SSD1306::vendor_config */ virtual void *vendor_config() = 0; /// Width of the device screen in pixels. int32_t width_; /// Height of the device screen in pixels. int32_t height_; /// RST GPIO pin number. int rst_num_; /// LVGL draw buffer size for the device. size_t lv_buf_size_; /// ESP LCD panel IO configuration. esp_lcd_panel_io_i2c_config_t esp_io_config_; private: /** * Initializes the ESP panel using vendor specific APIs and configurations. * This method should implement any setup logic specific to the device. * * @param config ESP LCD panel configuration. * @param io ESP LCD panel IO handle. * @param [out] panel ESP LCD panel handle output pointer location. */ virtual void init_panel(esp_lcd_panel_dev_config_t &config, esp_lcd_panel_io_handle_t io, esp_lcd_panel_handle_t &panel) = 0; }; #endif // PANEL_DEVICE_H