esp-who/examples/esp32-s3-eye/main/src/app_lcd.cpp

179 lines
5.1 KiB
C++

#include "app_lcd.hpp"
#include <string.h>
#include "esp_log.h"
#include "esp_camera.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "logo_en_240x240_lcd.h"
static const char TAG[] = "App/LCD";
AppLCD::AppLCD(AppButton *key,
AppSpeech *speech,
QueueHandle_t queue_i,
QueueHandle_t queue_o,
void (*callback)(camera_fb_t *)) : Frame(queue_i, queue_o, callback),
key(key),
speech(speech),
switch_on(false)
{
do
{
spi_config_t bus_conf = {
.miso_io_num = (gpio_num_t)BOARD_LCD_MISO,
.mosi_io_num = (gpio_num_t)BOARD_LCD_MOSI,
.sclk_io_num = (gpio_num_t)BOARD_LCD_SCK,
.max_transfer_sz = 2 * 240 * 240 + 10,
};
spi_bus_handle_t spi_bus = spi_bus_create(SPI2_HOST, &bus_conf);
scr_interface_spi_config_t spi_lcd_cfg = {
.spi_bus = spi_bus,
.pin_num_cs = BOARD_LCD_CS,
.pin_num_dc = BOARD_LCD_DC,
.clk_freq = 40 * 1000000,
.swap_data = 0,
};
scr_interface_driver_t *iface_drv;
scr_interface_create(SCREEN_IFACE_SPI, &spi_lcd_cfg, &iface_drv);
if (ESP_OK != scr_find_driver(SCREEN_CONTROLLER_ST7789, &this->driver))
{
ESP_LOGE(TAG, "screen find failed");
break;
}
scr_controller_config_t lcd_cfg = {
.interface_drv = iface_drv,
.pin_num_rst = BOARD_LCD_RST,
.pin_num_bckl = BOARD_LCD_BL,
.rst_active_level = 0,
.bckl_active_level = 0,
.width = 240,
.height = 240,
.offset_hor = 0,
.offset_ver = 0,
.rotate = (scr_dir_t)0,
};
if (ESP_OK != this->driver.init(&lcd_cfg))
{
ESP_LOGE(TAG, "screen initialize failed");
break;
}
scr_info_t lcd_info;
this->driver.get_info(&lcd_info);
ESP_LOGI(TAG, "Screen name:%s | width:%d | height:%d", lcd_info.name, lcd_info.width, lcd_info.height);
this->draw_color(0x000000);
vTaskDelay(pdMS_TO_TICKS(500));
this->draw_wallpaper();
vTaskDelay(pdMS_TO_TICKS(1000));
} while (0);
}
void AppLCD::draw_wallpaper()
{
uint16_t *pixels = (uint16_t *)heap_caps_malloc((logo_en_240x240_lcd_width * logo_en_240x240_lcd_height) * sizeof(uint16_t), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
if (NULL == pixels)
{
ESP_LOGE(TAG, "Memory for bitmap is not enough");
return;
}
memcpy(pixels, logo_en_240x240_lcd, (logo_en_240x240_lcd_width * logo_en_240x240_lcd_height) * sizeof(uint16_t));
this->driver.draw_bitmap(0, 0, logo_en_240x240_lcd_width, logo_en_240x240_lcd_height, (uint16_t *)pixels);
heap_caps_free(pixels);
this->paper_drawn = true;
}
void AppLCD::draw_color(int color)
{
scr_info_t lcd_info;
this->driver.get_info(&lcd_info);
uint16_t *buffer = (uint16_t *)malloc(lcd_info.width * sizeof(uint16_t));
if (buffer)
{
for (size_t i = 0; i < lcd_info.width; i++)
{
buffer[i] = color;
}
for (int y = 0; y < lcd_info.height; y++)
{
this->driver.draw_bitmap(0, y, lcd_info.width, 1, buffer);
}
free(buffer);
}
else
{
ESP_LOGE(TAG, "Memory for bitmap is not enough");
}
}
void AppLCD::update()
{
if (this->key->pressed > BUTTON_IDLE)
{
if (this->key->pressed == BUTTON_MENU)
{
this->switch_on = (this->key->menu == MENU_STOP_WORKING) ? false : true;
ESP_LOGD(TAG, "%s", this->switch_on ? "ON" : "OFF");
}
}
if (this->speech->command > COMMAND_NOT_DETECTED)
{
if (this->speech->command >= MENU_STOP_WORKING && this->speech->command <= MENU_MOTION_DETECTION)
{
this->switch_on = (this->speech->command == MENU_STOP_WORKING) ? false : true;
ESP_LOGD(TAG, "%s", this->switch_on ? "ON" : "OFF");
}
}
if (this->switch_on == false)
{
this->paper_drawn = false;
}
}
static void task(AppLCD *self)
{
ESP_LOGD(TAG, "Start");
camera_fb_t *frame = nullptr;
while (true)
{
if (self->queue_i == nullptr)
break;
if (xQueueReceive(self->queue_i, &frame, portMAX_DELAY))
{
if (self->switch_on)
self->driver.draw_bitmap(0, 0, frame->width, frame->height, (uint16_t *)frame->buf);
else if (self->paper_drawn == false)
self->draw_wallpaper();
if (self->queue_o)
xQueueSend(self->queue_o, &frame, portMAX_DELAY);
else
self->callback(frame);
}
}
ESP_LOGD(TAG, "Stop");
self->draw_wallpaper();
vTaskDelete(NULL);
}
void AppLCD::run()
{
xTaskCreatePinnedToCore((TaskFunction_t)task, TAG, 2 * 1024, this, 5, NULL, 1);
}