在当前的Cat.1设备上支持LVGL的方法:
当前的移植仅适用于的LCD驱动为st7735s
1:把LVGL源码放入应用程序所在目录
2:修改lvgl中的CMakelist.txt
Code: Select all
# Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA").
# All rights reserved.
#
# This software is supplied "AS IS" without any warranties.
# RDA assumes no responsibility or liability for the use of the software,
# conveys no license or title under any patent, copyright, or mask work
# right to the product. RDA reserves the right to make changes in the
# software without notification. RDA also make no representation or
# warranty that such application will be suitable for the specified use
# without further testing or modification.
# 用户需要根据实际内容进行修改
set (CONFIG_LV_GUI_THREAD_STACK_SIZE 8192)
set (CONFIG_LV_GUI_THREAD_EVENT_COUNT 16)
set (CONFIG_LV_GUI_HOR_RES 160)
set (CONFIG_LV_GUI_VER_RES 128)
set (CONFIG_LV_GUI_SCREEN_OFF_TIMEOUT 5000)
configure_file(include/lv_gui_config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/include/lv_gui_config.h)
function(add_app_libraries)
get_property(app_libraries GLOBAL PROPERTY app_libraries)
set_property(GLOBAL PROPERTY app_libraries ${app_libraries} ${ARGN})
endfunction()
set(target lvgl)
add_app_libraries($<TARGET_FILE:${target}>)
add_library(${target} STATIC ${dummy_c_file})
set_target_properties(${target} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${out_lib_dir})
target_compile_definitions(${target} PRIVATE OSI_LOG_TAG=LOG_TAG_LVGL)
target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SRC_DIR} lvgl include)
target_sources(${target} PRIVATE
lvgl/src/lv_core/lv_disp.c
lvgl/src/lv_core/lv_group.c
lvgl/src/lv_core/lv_indev.c
lvgl/src/lv_core/lv_obj.c
lvgl/src/lv_core/lv_refr.c
lvgl/src/lv_core/lv_style.c
lvgl/src/lv_draw/lv_draw_arc.c
lvgl/src/lv_draw/lv_draw_blend.c
lvgl/src/lv_draw/lv_draw_img.c
lvgl/src/lv_draw/lv_draw_label.c
lvgl/src/lv_draw/lv_draw_line.c
lvgl/src/lv_draw/lv_draw_mask.c
lvgl/src/lv_draw/lv_draw_rect.c
lvgl/src/lv_draw/lv_draw_triangle.c
lvgl/src/lv_draw/lv_img_buf.c
lvgl/src/lv_draw/lv_img_cache.c
lvgl/src/lv_draw/lv_img_decoder.c
lvgl/src/lv_font/lv_font.c
lvgl/src/lv_font/lv_font_dejavu_16_persian_hebrew.c
lvgl/src/lv_font/lv_font_fmt_txt.c
lvgl/src/lv_font/lv_font_loader.c
lvgl/src/lv_font/lv_font_montserrat_10.c
lvgl/src/lv_font/lv_font_montserrat_12.c
lvgl/src/lv_font/lv_font_montserrat_12_subpx.c
lvgl/src/lv_font/lv_font_montserrat_14.c
lvgl/src/lv_font/lv_font_montserrat_16.c
lvgl/src/lv_font/lv_font_montserrat_18.c
lvgl/src/lv_font/lv_font_montserrat_20.c
lvgl/src/lv_font/lv_font_montserrat_22.c
lvgl/src/lv_font/lv_font_montserrat_24.c
lvgl/src/lv_font/lv_font_montserrat_26.c
lvgl/src/lv_font/lv_font_montserrat_28.c
lvgl/src/lv_font/lv_font_montserrat_28_compressed.c
lvgl/src/lv_font/lv_font_montserrat_30.c
lvgl/src/lv_font/lv_font_montserrat_32.c
lvgl/src/lv_font/lv_font_montserrat_34.c
lvgl/src/lv_font/lv_font_montserrat_36.c
lvgl/src/lv_font/lv_font_montserrat_38.c
lvgl/src/lv_font/lv_font_montserrat_40.c
lvgl/src/lv_font/lv_font_montserrat_42.c
lvgl/src/lv_font/lv_font_montserrat_44.c
lvgl/src/lv_font/lv_font_montserrat_46.c
lvgl/src/lv_font/lv_font_montserrat_48.c
lvgl/src/lv_font/lv_font_montserrat_8.c
lvgl/src/lv_font/lv_font_simsun_16_cjk.c
lvgl/src/lv_font/lv_font_unscii_16.c
lvgl/src/lv_font/lv_font_unscii_8.c
lvgl/src/lv_gpu/lv_gpu_nxp_pxp.c
lvgl/src/lv_gpu/lv_gpu_nxp_pxp_osa.c
lvgl/src/lv_gpu/lv_gpu_nxp_vglite.c
lvgl/src/lv_gpu/lv_gpu_stm32_dma2d.c
lvgl/src/lv_hal/lv_hal_disp.c
lvgl/src/lv_hal/lv_hal_indev.c
lvgl/src/lv_hal/lv_hal_tick.c
lvgl/src/lv_misc/lv_anim.c
lvgl/src/lv_misc/lv_area.c
lvgl/src/lv_misc/lv_async.c
lvgl/src/lv_misc/lv_bidi.c
lvgl/src/lv_misc/lv_color.c
lvgl/src/lv_misc/lv_debug.c
lvgl/src/lv_misc/lv_fs.c
lvgl/src/lv_misc/lv_gc.c
lvgl/src/lv_misc/lv_ll.c
lvgl/src/lv_misc/lv_log.c
lvgl/src/lv_misc/lv_math.c
lvgl/src/lv_misc/lv_mem.c
lvgl/src/lv_misc/lv_printf.c
lvgl/src/lv_misc/lv_task.c
lvgl/src/lv_misc/lv_templ.c
lvgl/src/lv_misc/lv_txt_ap.c
lvgl/src/lv_misc/lv_txt.c
lvgl/src/lv_misc/lv_utils.c
lvgl/src/lv_themes/lv_theme.c
lvgl/src/lv_themes/lv_theme_empty.c
lvgl/src/lv_themes/lv_theme_material.c
lvgl/src/lv_themes/lv_theme_mono.c
lvgl/src/lv_themes/lv_theme_template.c
lvgl/src/lv_widgets/lv_arc.c
lvgl/src/lv_widgets/lv_bar.c
lvgl/src/lv_widgets/lv_btn.c
lvgl/src/lv_widgets/lv_btnmatrix.c
lvgl/src/lv_widgets/lv_calendar.c
lvgl/src/lv_widgets/lv_canvas.c
lvgl/src/lv_widgets/lv_chart.c
lvgl/src/lv_widgets/lv_checkbox.c
lvgl/src/lv_widgets/lv_cont.c
lvgl/src/lv_widgets/lv_cpicker.c
lvgl/src/lv_widgets/lv_dropdown.c
lvgl/src/lv_widgets/lv_gauge.c
lvgl/src/lv_widgets/lv_imgbtn.c
lvgl/src/lv_widgets/lv_img.c
lvgl/src/lv_widgets/lv_keyboard.c
lvgl/src/lv_widgets/lv_label.c
lvgl/src/lv_widgets/lv_led.c
lvgl/src/lv_widgets/lv_line.c
lvgl/src/lv_widgets/lv_linemeter.c
lvgl/src/lv_widgets/lv_list.c
lvgl/src/lv_widgets/lv_msgbox.c
lvgl/src/lv_widgets/lv_objmask.c
lvgl/src/lv_widgets/lv_objx_templ.c
lvgl/src/lv_widgets/lv_page.c
lvgl/src/lv_widgets/lv_roller.c
lvgl/src/lv_widgets/lv_slider.c
lvgl/src/lv_widgets/lv_spinbox.c
lvgl/src/lv_widgets/lv_spinner.c
lvgl/src/lv_widgets/lv_switch.c
lvgl/src/lv_widgets/lv_table.c
lvgl/src/lv_widgets/lv_tabview.c
lvgl/src/lv_widgets/lv_textarea.c
lvgl/src/lv_widgets/lv_tileview.c
lvgl/src/lv_widgets/lv_win.c
)
# 需要根据自己实现
target_sources(${target} PRIVATE lv_port/lv_gui_main.c)
3、修改lv_conf.h
Code: Select all
#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM == 1
#define LV_TICK_CUSTOM_INCLUDE "tal_system.h" /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR ((uint32_t)tal_system_get_millisecond()) /*Expression evaluating to current system time in ms*/
#endif /*LV_TICK_CUSTOM*/
4、修改lvgl中的移植文件lv_gui_main.c
Code: Select all
/**
* @file lv_gui_main.c
* @brief
* @version 0.1
* @date 2023-03-06
*
* @copyright Copyright (c) 2023-2023 Tuya Inc. All Rights Reserved.
*
* Permission is hereby granted, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), Under the premise of complying
* with the license of the third-party open source software contained in the software,
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software.
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
*/
// #define OSI_LOCAL_LOG_LEVEL OSI_LOG_LEVEL_DEBUG
#include "lv_gui_main.h"
#include "tal_log.h"
#include "tal_system.h"
#include "tal_thread.h"
#include "tal_sw_timer.h"
#include "tal_queue.h"
#include "tuya_cat1_dev_lcd.h"
#include "tal_cellular_keypad.h"
#include "tkl_timer.h"
#include "lvgl.h"
#include "osi_api.h"
#include "osi_log.h"
#include <string.h>
#include <stdlib.h>
#define LV_INDEXED_CHROMA 1
#define WAIT_FOREVER 0xFFFFffff
typedef struct
{
BOOL_T screen_on; // state of screen on
BOOL_T keypad_pending; // keypad pending, set in ISR, clear in thread
BOOL_T anim_inactive; // property of whether animation is regarded as inactive
TUYA_CAT1_LCD_DRV_T *lcd; // LCD instance
THREAD_HANDLE thread; // gui thread
TIMER_ID task_timer; // timer to trigger task handler
QUEUE_HANDLE lv_queue;
TUYA_CAT1_LCD_VIDEO_LAYER_T vl; // extern video layer
lv_disp_buf_t disp_buf; // display buffer
lv_disp_t *disp; // display device
lv_indev_t *keypad; // keypad device
TUYA_KEYMAP_E last_key; // last key from ISR
TUYA_KEYSTATE_E last_key_state; // last key state from ISR
uint32_t screen_on_users; // screen on user bitmap
uint32_t inactive_timeout; // property of inactive timeout
} lvGuiContext_t;
typedef struct
{
uint8_t keypad;
uint8_t lv_key;
} lvGuiKeypadMap_t;
static const lvGuiKeypadMap_t gLvKeyMap[] = {
{TUYA_KEY_MAP_OK, LV_KEY_ENTER},
{TUYA_KEY_MAP_LEFT, LV_KEY_LEFT},
{TUYA_KEY_MAP_RIGHT, LV_KEY_RIGHT},
{TUYA_KEY_MAP_UP, LV_KEY_UP},
{TUYA_KEY_MAP_DOWN, LV_KEY_DOWN},
};
static lvGuiContext_t gLvGuiCtx;
/**
* flush display forcedly
*/
enum
{
/** RGB565 in little endian, [15:11] R, [10:5] G, [4:0] B */
DRV_LCD_IN_FMT_RGB565,
/** ARGB8888 in little endian, [31:24] A, [23:16] R, [15:8] G, [7:0] B */
DRV_LCD_IN_FMT_ARGB8888,
/** UYVY pixel-packed format */
DRV_LCD_IN_FMT_UYVY,
/** YUYV pixel-packed format */
DRV_LCD_IN_FMT_YUYV,
/** IYUV planar format */
DRV_LCD_IN_FMT_IYUV,
};
#define LCD_DIR TUYA_CAT1_LCD_DIR_XINV
#define LCD_ID 0x7c89f0
STATIC VOID prvSt7735sSetDir(drvLcd_t *d, TUYA_CAT1_LCD_DIR_T dir)
{
// MY MX MV ML BGR MH x x
uint8_t ctrl = 0x8; // default value except MY/MX/MV
if (dir & 1)
ctrl |= 0x80;
if (dir & 2)
ctrl |= 0x40;
if (dir & 4)
ctrl |= 0x20;
drvLcdWriteCmd(d, 0x36); // memory access control
drvLcdWriteData(d, ctrl);
}
STATIC VOID prvSt7735sInit(drvLcd_t *d)
{
drvLcdWriteCmd(d, 0x11); // sleep out
osiThreadSleep(100); // delay 100ms
// frame rate
drvLcdWriteCmd(d, 0xb1);
drvLcdWriteData(d, 0x05);
drvLcdWriteData(d, 0x3c);
drvLcdWriteData(d, 0x3c);
drvLcdWriteCmd(d, 0xb2);
drvLcdWriteData(d, 0x05);
drvLcdWriteData(d, 0x3c);
drvLcdWriteData(d, 0x3c);
drvLcdWriteCmd(d, 0xb3);
drvLcdWriteData(d, 0x05);
drvLcdWriteData(d, 0x3c);
drvLcdWriteData(d, 0x3c);
drvLcdWriteData(d, 0x05);
drvLcdWriteData(d, 0x3c);
drvLcdWriteData(d, 0x3c);
drvLcdWriteCmd(d, 0xb4); // dot inversion
drvLcdWriteData(d, 0x03);
drvLcdWriteCmd(d, 0xc0);
drvLcdWriteData(d, 0x28);
drvLcdWriteData(d, 0x08);
drvLcdWriteData(d, 0x04);
drvLcdWriteCmd(d, 0xc1);
drvLcdWriteData(d, 0xc0);
drvLcdWriteCmd(d, 0xc2);
drvLcdWriteData(d, 0x0d);
drvLcdWriteData(d, 0x00);
drvLcdWriteCmd(d, 0xc3);
drvLcdWriteData(d, 0x8d);
drvLcdWriteData(d, 0x2a);
drvLcdWriteCmd(d, 0xc4);
drvLcdWriteData(d, 0x8d);
drvLcdWriteData(d, 0xee);
drvLcdWriteCmd(d, 0xc5);
drvLcdWriteData(d, 0x1a);
prvSt7735sSetDir(d, LCD_DIR);
drvLcdWriteCmd(d, 0xe0);
drvLcdWriteData(d, 0x04);
drvLcdWriteData(d, 0x22);
drvLcdWriteData(d, 0x07);
drvLcdWriteData(d, 0x0A);
drvLcdWriteData(d, 0x2E);
drvLcdWriteData(d, 0x30);
drvLcdWriteData(d, 0x25);
drvLcdWriteData(d, 0x2A);
drvLcdWriteData(d, 0x28);
drvLcdWriteData(d, 0x26);
drvLcdWriteData(d, 0x2E);
drvLcdWriteData(d, 0x3A);
drvLcdWriteData(d, 0x00);
drvLcdWriteData(d, 0x01);
drvLcdWriteData(d, 0x03);
drvLcdWriteData(d, 0x13);
drvLcdWriteCmd(d, 0xE1);
drvLcdWriteData(d, 0x04);
drvLcdWriteData(d, 0x16);
drvLcdWriteData(d, 0x06);
drvLcdWriteData(d, 0x0D);
drvLcdWriteData(d, 0x2D);
drvLcdWriteData(d, 0x26);
drvLcdWriteData(d, 0x23);
drvLcdWriteData(d, 0x27);
drvLcdWriteData(d, 0x27);
drvLcdWriteData(d, 0x25);
drvLcdWriteData(d, 0x2D);
drvLcdWriteData(d, 0x3B);
drvLcdWriteData(d, 0x00);
drvLcdWriteData(d, 0x01);
drvLcdWriteData(d, 0x04);
drvLcdWriteData(d, 0x13);
drvLcdWriteCmd(d, 0x3A); //65k mode
drvLcdWriteData(d, 0x05);
drvLcdWriteCmd(d, 0x29); //Display on
tal_system_sleep(20);
drvLcdWriteCmd(d, 0x2c);
}
STATIC VOID prvSt7735sBlitPrepare(drvLcd_t *d, TUYA_CAT1_LCD_DIR_T dir, CONST TUYA_CAT1_LCD_AREA_T *roi)
{
// TAL_PR_NOTICE("St7735s dir/%d roi/%d/%d/%d/%d", dir, roi->x, roi->y, roi->w, roi->h);
prvSt7735sSetDir(d, dir);
uint16_t left = roi->x;
uint16_t right = roi->x + roi->w - 1;
uint16_t top = roi->y;
uint16_t bot = roi->y + roi->h - 1;
drvLcdWriteCmd(d, 0x2a); // set hori start , end (left, right)
drvLcdWriteData(d, (left >> 8) & 0xff); // left high 8 b
drvLcdWriteData(d, left & 0xff); // left low 8 b
drvLcdWriteData(d, (right >> 8) & 0xff); // right high 8 b
drvLcdWriteData(d, right & 0xff); // right low 8 b
drvLcdWriteCmd(d, 0x2b); // set vert start , end (top, bot)
drvLcdWriteData(d, (top >> 8) & 0xff); // top high 8 b
drvLcdWriteData(d, top & 0xff); // top low 8 b
drvLcdWriteData(d, (bot >> 8) & 0xff); // bot high 8 b
drvLcdWriteData(d, bot & 0xff); // bot low 8 b
drvLcdWriteCmd(d, 0x2c); // recover memory write mode
}
STATIC UINT_T prvSt7735sReadId(drvLcd_t *d)
{
UINT8_T id[4];
drvLcdReadData(d, 0x04, id, 4);
UINT_T dev_id = (id[3] << 16) | (id[2] << 8) | id[1];
TAL_PR_NOTICE("St7735s read id: 0x%08x", dev_id);
return dev_id;
}
STATIC BOOL_T prvSt7735sProbe(drvLcd_t *d)
{
TAL_PR_NOTICE("St7735s probe");
return prvSt7735sReadId(d) == LCD_ID;
}
// 定义ST7735S 操作函数及参数
CONST TUYA_CAT1_LCD_DRV_T gLcdSt7735sDesc = {
.ops = {
.probe = prvSt7735sProbe,
.init = prvSt7735sInit,
.blit_prepare = prvSt7735sBlitPrepare,
},
.name = "ST7735S",
.dev_id = LCD_ID,
.reset_us = 120 * 1000,
.init_delay_us = 100 * 1000,
.width = 128,
.height = 160,
.fmt = TUYA_CAT1_LCD_FMT_16_RGB565,
.dir = LCD_DIR,
.line_mode = TUYA_CAT1_LCD_SPI_4WIRE,
.fmark_enabled = FALSE,
.fmark_delay = 0x2a000,
.freq = 10000000,
.frame_us = (UINT_T)(1000000 / 28.0),
};
static void prvDispForceFlush(void)
{
lvGuiContext_t *d = &gLvGuiCtx;
TUYA_CAT1_LCD_AREA_T roi = {
.x = 0,
.y = 0,
.w = d->disp->driver.hor_res,
.h = d->disp->driver.ver_res,
};
TUYA_CAT1_LCD_OVERLAY_T ovl = {
.buf = d->disp_buf.buf1,
.enabled = TRUE,
.in_fmt = DRV_LCD_IN_FMT_RGB565,
.alpha = 255,
.key_en = LV_INDEXED_CHROMA,
.key_color = lv_color_to16(LV_COLOR_TRANSP),
.stride = roi.w,
.out = roi,
};
TUYA_CAT1_LCD_LAYERS_T lcd_layers={
.vl = &d->vl,
.ovl = {NULL,NULL,&ovl},
.layer_roi = roi,
.screen_roi = roi,
};
tuya_cat1_lcd_flush(&lcd_layers,TRUE);
}
/**
* display device flush_cb
*/
static void prvDispFlush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
lvGuiContext_t *d = &gLvGuiCtx;
TUYA_CAT1_LCD_AREA_T roi = {
.x = area->x1,
.y = area->y1,
.w = area->x2 - area->x1 + 1,
.h = area->y2 - area->y1 + 1,
};
TUYA_CAT1_LCD_OVERLAY_T ovl = {
.buf = color_p,
.enabled = TRUE,
.in_fmt = DRV_LCD_IN_FMT_RGB565,
.alpha = 255,
.key_en = LV_INDEXED_CHROMA,
.key_color = lv_color_to16(LV_COLOR_TRANSP),
.stride = roi.w,
.out = roi,
};
TUYA_CAT1_LCD_LAYERS_T lcd_layers = {
.vl = &d->vl,
.ovl = {NULL, NULL, &ovl},
.layer_roi = roi,
.screen_roi = roi,
};
tuya_cat1_lcd_flush(&lcd_layers,TRUE);
lv_disp_flush_ready(disp);
}
static BOOL_T hal_lcd_init(void)
{
tuya_cat1_lcd_driver_register(&gLcdSt7735sDesc);
TAL_PR_DEBUG("prvLvInitLcd start");
if (!tuya_cat1_lcd_open()) {
TAL_PR_DEBUG("tuya_cat1_lcd_open failed");
return FALSE;
}
// 根据实际情况处理
tuya_cat1_lcd_set_direction(TUYA_CAT1_LCD_DIR_XINV);
return TRUE;
}
/**
* initialize LCD display device
*/
static BOOL_T prvLvInitLcd(void)
{
lvGuiContext_t *d = &gLvGuiCtx;
TUYA_CAT1_LCD_INFO_T panel_info;
if (!tuya_cat1_lcd_get_info(&panel_info)) {
TAL_PR_DEBUG("tuya_cat1_lcd_get_info failed");
return FALSE;
}
unsigned pixel_cnt = panel_info.width * panel_info.height;
lv_color_t *buf = (lv_color_t *)malloc(pixel_cnt * sizeof(lv_color_t));
if (buf == NULL) {
TAL_PR_DEBUG("malloc lv_color_t buf failed");
return FALSE;
}
lv_disp_buf_init(&d->disp_buf, buf, buf, pixel_cnt);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = prvDispFlush;
disp_drv.buffer = &d->disp_buf;
disp_drv.hor_res = 128;
disp_drv.ver_res = 160;
d->disp = lv_disp_drv_register(&disp_drv); // pointer copy
lvGuiScreenOn();
TAL_PR_DEBUG("prvLvInitLcd completed");
return TRUE;
}
/**
* keypad device read_cb
*/
static bool prvLvKeypadRead(lv_indev_drv_t *kp, lv_indev_data_t *data)
{
lvGuiContext_t *d = &gLvGuiCtx;
uint32_t critical = osiEnterCritical();
TUYA_KEYMAP_E last_key = d->last_key;
TUYA_KEYSTATE_E last_key_state = d->last_key_state;
BOOL_T keypad_pending = d->keypad_pending;
d->keypad_pending = false;
osiExitCritical(critical);
if (keypad_pending)
{
data->state = (last_key_state & TUYA_KEY_RELEASE) ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
data->key = 0xff;
for (unsigned n = 0; n < OSI_ARRAY_SIZE(gLvKeyMap); n++)
{
if (gLvKeyMap[n].keypad == last_key)
{
data->key = gLvKeyMap[n].lv_key;
break;
}
}
lvGuiScreenOn();
}
// no more to be read
return false;
}
VOID tuyaKeypadCallback(TUYA_KEYMAP_E keyId, TUYA_KEYSTATE_E state,
void *ctx)
{
lvGuiContext_t *d = &gLvGuiCtx;
TAL_PR_DEBUG("keyId = %d state = %d",keyId,state);
d->last_key = keyId;
d->last_key_state = state;
d->keypad_pending = TRUE;
}
/**
* initialize keypad device
*/
static BOOL_T prvLvInitKeypad(void)
{
lvGuiContext_t *d = &gLvGuiCtx;
lv_indev_drv_t kp_drv;
lv_indev_drv_init(&kp_drv);
kp_drv.type = LV_INDEV_TYPE_KEYPAD;
kp_drv.read_cb = prvLvKeypadRead;
d->keypad = lv_indev_drv_register(&kp_drv); // pointer copy
tal_cellular_keypad_init(NULL);
tkl_cellular_keypad_key_listener_add(TUYA_KEY_MAP_LEFT,tuyaKeypadCallback,NULL);
tkl_cellular_keypad_key_listener_add(TUYA_KEY_MAP_RIGHT,tuyaKeypadCallback,NULL);
tkl_cellular_keypad_key_listener_add(TUYA_KEY_MAP_UP,tuyaKeypadCallback,NULL);
tkl_cellular_keypad_key_listener_add(TUYA_KEY_MAP_DOWN,tuyaKeypadCallback,NULL);
tkl_cellular_keypad_key_listener_add(TUYA_KEY_MAP_OK,tuyaKeypadCallback,NULL);
return TRUE;
}
/**
* run littlevgl task handler
*/
static void prvLvTaskHandler(TIMER_ID timer_id, VOID_T *arg)
{
lvGuiContext_t *d = &gLvGuiCtx;
lv_task_handler();
unsigned next_run = lv_task_get_tick_next_run();
tal_sw_timer_start(d->task_timer,next_run,TAL_TIMER_ONCE);
lv_refr_now(d->disp);
}
/**
* whether inactive timeout
*/
static BOOL_T prvIsInactiveTimeout(void)
{
lvGuiContext_t *d = &gLvGuiCtx;
if (d->screen_on_users != 0)
return FALSE;
if (d->inactive_timeout == 0)
return FALSE;
if (!d->anim_inactive && lv_anim_count_running())
return FALSE;
return lv_disp_get_inactive_time(d->disp) > d->inactive_timeout;
}
/**
* gui thread entry
*/
static void prvLvThreadEntry(void *param)
{
lvGuiContext_t *d = &gLvGuiCtx;
d->thread = osiThreadCurrent();
tal_sw_timer_create(prvLvTaskHandler,NULL,&d->task_timer);
lv_init();
prvLvInitLcd();
prvLvInitKeypad();
lvGuiCreate_t create = (lvGuiCreate_t)param;
if (create != NULL)
create();
// osiTimerStart(d->task_timer, 0);
tal_sw_timer_start(d->task_timer,100,TAL_TIMER_ONCE);
lv_disp_trig_activity(d->disp);
for (;;)
{
lvGui_event event;
event.id = OSI_EVENT_ID_NONE;
tal_queue_fetch(d->lv_queue,&event,WAIT_FOREVER);
// osiEventWait(d->thread, &event);
if (event.id == OSI_EVENT_ID_QUIT)
break;
if (d->screen_on && prvIsInactiveTimeout())
{
TAL_PR_DEBUG("inactive timeout, screen off");
lvGuiScreenOff();
}
}
tal_thread_delete(d->thread);
}
/**
* start gui based on littlevgl
*/
BOOL_T lvGuiInit(lvGuiCreate_t create)
{
lvGuiContext_t *d = &gLvGuiCtx;
OPERATE_RET ret = OPRT_OK;
if (!hal_lcd_init()) {
TAL_PR_ERR("hal lcd init failed");
return FALSE;
}
d->screen_on = TRUE;
d->keypad_pending = FALSE;
d->anim_inactive = FALSE;
d->last_key = 0xff;
d->last_key_state = TUYA_KEY_RELEASE;
d->screen_on_users = 0;
d->inactive_timeout = CONFIG_LV_GUI_SCREEN_OFF_TIMEOUT*6;
ret = tal_queue_create_init(&d->lv_queue,sizeof(lvGui_event),CONFIG_LV_GUI_THREAD_EVENT_COUNT);
if (ret != OPRT_OK) {
TAL_PR_ERR("create prvLvThreadEntry failed ret = %d",ret);
return ret;
}
THREAD_CFG_T cfg = {0};
cfg.priority = OSI_PRIORITY_NORMAL;
cfg.stackDepth = CONFIG_LV_GUI_THREAD_STACK_SIZE;
cfg.thrdname = "lvgl";
ret = tal_thread_create_and_start(&d->thread,NULL,NULL,prvLvThreadEntry,create,&cfg);
if (ret != OPRT_OK) {
TAL_PR_ERR("create prvLvThreadEntry failed ret = %d",ret);
tal_queue_free(d->lv_queue);
return ret;
}
return ret;
}
/**
* get littlevgl gui thread
*/
THREAD_HANDLE lvGuiGetThread(void)
{
lvGuiContext_t *d = &gLvGuiCtx;
return d->thread;
}
/**
* get keypad input device
*/
lv_indev_t *lvGuiGetKeyPad(void)
{
lvGuiContext_t *d = &gLvGuiCtx;
return d->keypad;
}
/**
* send event to gui thread
*/
void lvGuiSendEvent(const lvGui_event *evt)
{
lvGuiContext_t *d = &gLvGuiCtx;
// osiEventSend(d->thread, evt);
tal_queue_post(d->lv_queue,&evt,WAIT_FOREVER);
}
/**
* request screen on
*/
BOOL_T lvGuiRequestSceenOn(uint8_t id)
{
lvGuiContext_t *d = &gLvGuiCtx;
if (id > 31)
return FALSE;
unsigned mask = (1 << id);
d->screen_on_users |= mask;
return TRUE;
}
/**
* release screen on request
*/
BOOL_T lvGuiReleaseScreenOn(uint8_t id)
{
lvGuiContext_t *d = &gLvGuiCtx;
if (id > 31)
return FALSE;
unsigned mask = (1 << id);
d->screen_on_users &= ~mask;
return TRUE;
}
/**
* turn off screen
*/
void lvGuiScreenOff(void)
{
lvGuiContext_t *d = &gLvGuiCtx;
if (!d->screen_on)
return;
TAL_PR_DEBUG("screen off");
tuya_cat1_lcd_backlight_enable(FALSE);
tuya_cat1_lcd_sleep_enable(TRUE);
d->screen_on = FALSE;
}
/**
* turn on screen
*/
void lvGuiScreenOn(void)
{
lvGuiContext_t *d = &gLvGuiCtx;
if (d->screen_on)
return;
TAL_PR_DEBUG("screen on");
tuya_cat1_lcd_sleep_enable(FALSE);
prvDispForceFlush();
tuya_cat1_lcd_backlight_enable(FALSE);
d->screen_on = TRUE;
}
/**
* set screen off timeout at inactive
*/
void lvGuiSetInactiveTimeout(unsigned timeout)
{
lvGuiContext_t *d = &gLvGuiCtx;
d->inactive_timeout = timeout;
}
/**
* set whether animation is regarded as inactive
*/
void lvGuiSetAnimationInactive(BOOL_T inactive)
{
lvGuiContext_t *d = &gLvGuiCtx;
d->anim_inactive = inactive;
}
5、修改lvgl中lv_gui_main.h
Code: Select all
/**
* @file lv_gui_main.h
* @brief
* @version 0.1
* @date 2023-03-06
*
* @copyright Copyright (c) 2023-2023 Tuya Inc. All Rights Reserved.
*
* Permission is hereby granted, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), Under the premise of complying
* with the license of the third-party open source software contained in the software,
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software.
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
*/
#ifndef _LV_GUI_MAIN_H_
#define _LV_GUI_MAIN_H_
#include "tuya_cloud_types.h"
#include "lv_gui_config.h"
#include "tal_thread.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
uint32_t id; ///< event identifier
uint32_t param1; ///< 1st parameter
uint32_t param2; ///< 2nd parameter
uint32_t param3; ///< 3rd parameter
} lvGui_event;
/**
* \brief forward declaration
*/
struct _lv_indev_t;
/**
* \brief function prototype for gui creation
*/
typedef void (*lvGuiCreate_t)(void);
/**
* \brief start gui based on littlevgl
*
* It will create gui thread, initialize littlevgl, and optional call gui
* creation function \p create.
*
* LCD should be initialized before this, back light should be enabled. And
* usually quick logo has been shown. Gui thread will blit to LCD directly.
*
* \param create gui creation function
*/
BOOL_T lvGuiInit(lvGuiCreate_t create);
/**
* \brief terminate littlevgl gui
*
* Most likely, it won't be called.
*/
void lvGuiDeinit(void);
/**
* \brief get littlevgl gui thread
*
* \return
* - littlevgl gui thread
*/
THREAD_HANDLE lvGuiGetThread(void);
/**
* \brief get keypad input device
* \return
* - keypad device
*/
struct _lv_indev_t *lvGuiGetKeyPad(void);
/**
* \brief send event to gui thread
*/
void lvGuiSendEvent(const lvGui_event *evt);
/**
* \brief request screen on
*
* It is for an application to request the screen on even there are no
* user inputs.
*
* \p id is the identification of application. In the system, it should
* be unique. Internally, 32bits bitmap is used to record this. So, it
* should be inside [0,31].
*
* The request is not counting. That is, for a given application id,
* event there are multiple calls, single call of \p lvGuiReleaseScreenOn
* will clear the request.
*
* \param id application id
* \return
* - true on success
* - false on invalid parameter
*/
BOOL_T lvGuiRequestSceenOn(uint8_t id);
/**
* \brief release screen on request
*
* \param id application id
* \return
* - true on success
* - false on invalid parameter
*/
BOOL_T lvGuiReleaseScreenOn(uint8_t id);
/**
* \brief turn on screen
*
* When screen is already turned on, it will do nothing.
*/
void lvGuiScreenOn(void);
/**
* \brief turn off screen
*
* When screen is already turned off, it will do nothing.
*/
void lvGuiScreenOff(void);
/**
* \brief set screen off timeout at inactive
*
* It can change the default value. When \p timeout is 0, screen won't be
* turned off by inactive timeout.
*
* \param timeout inactive screen off timeout, 0 for never timeout
*/
void lvGuiSetInactiveTimeout(unsigned timeout);
/**
* \brief set whether animation is regarded as inactive
*
* When \p inactive is true, animation update won't be regarded as *active*.
* The inactive screen off timer will still count down even there are
* animations. Otherwise, inactive screen off timer will stop counting when
* there are animation.
*
* \param inactive animation will be regarded as inactive
*/
void lvGuiSetAnimationInactive(BOOL_T inactive);
#ifdef __cplusplus
}
#endif
#endif
6、建立UI页面代码
Code: Select all
/* Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA").
* All rights reserved.
*
* This software is supplied "AS IS" without any warranties.
* RDA assumes no responsibility or liability for the use of the software,
* conveys no license or title under any patent, copyright, or mask work
* right to the product. RDA reserves the right to make changes in the
* software without notification. RDA also make no representation or
* warranty that such application will be suitable for the specified use
* without further testing or modification.
*/
#include "lv_gui_main.h"
#include "lvgl.h"
#include "tal_log.h"
#include <string.h>
#include <stdlib.h>
// This example from https://github.com/littlevgl/lv_examples
static void event_handler(lv_obj_t * obj, lv_event_t event)
{
if(event == LV_EVENT_CLICKED) {
TAL_PR_DEBUG("Clicked");
}
else if(event == LV_EVENT_VALUE_CHANGED) {
TAL_PR_DEBUG("Toggled");
}
}
void lv_ex_btn_1(void)
{
lv_obj_t * label;
lv_obj_t * btn1 = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_event_cb(btn1, event_handler);
lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, -40);
label = lv_label_create(btn1, NULL);
lv_label_set_text(label, "Button");
lv_obj_t * btn2 = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_event_cb(btn2, event_handler);
lv_obj_align(btn2, NULL, LV_ALIGN_CENTER, 0, 40);
lv_btn_set_checkable(btn2, true);
lv_btn_toggle(btn2);
lv_btn_set_fit2(btn2, LV_FIT_NONE, LV_FIT_TIGHT);
label = lv_label_create(btn2, NULL);
lv_label_set_text(label, "Toggled");
}
void lv_ex_line_1(void)
{
/*Create an array for the points of the line*/
static lv_point_t line_points[] = { {0, 0}, {0, 127}, {127, 156}, {127, 0}, {0, 0}};
/*Create style*/
static lv_style_t style_line;
lv_style_init(&style_line);
lv_style_set_line_width(&style_line, LV_STATE_DEFAULT, 1);
lv_style_set_line_color(&style_line, LV_STATE_DEFAULT, LV_COLOR_BLUE);
lv_style_set_line_rounded(&style_line, LV_STATE_DEFAULT, true);
/*Create a line and apply the new style*/
lv_obj_t * line1;
line1 = lv_line_create(lv_scr_act(), NULL);
lv_line_set_points(line1, line_points, 5); /*Set the points*/
lv_obj_add_style(line1, LV_LINE_PART_MAIN, &style_line); /*Set the points*/
lv_obj_align(line1, NULL, LV_ALIGN_CENTER, 0, 0);
}
static void calendar_event_handler(lv_obj_t * obj, lv_event_t event)
{
if(event == LV_EVENT_VALUE_CHANGED) {
lv_calendar_date_t * date = lv_calendar_get_pressed_date(obj);
if(date) {
TAL_PR_DEBUG( "Clicked date: %02d.%02d.%d", date->day, date->month, date->year);
}
}
}
void lv_ex_calendar_1(void)
{
lv_obj_t * calendar = lv_calendar_create(lv_scr_act(), NULL);
lv_obj_set_size(calendar, 128, 160);
lv_obj_align(calendar, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_event_cb(calendar, calendar_event_handler);
/*Make the date number smaller to be sure they fit into their area*/
lv_obj_set_style_local_text_font(calendar, LV_CALENDAR_PART_DATE, LV_STATE_DEFAULT, lv_theme_get_font_small());
/*Set today's date*/
lv_calendar_date_t today;
today.year = 2018;
today.month = 10;
today.day = 23;
lv_calendar_set_today_date(calendar, &today);
lv_calendar_set_showed_date(calendar, &today);
/*Highlight a few days*/
static lv_calendar_date_t highlighted_days[3]; /*Only its pointer will be saved so should be static*/
highlighted_days[0].year = 2018;
highlighted_days[0].month = 10;
highlighted_days[0].day = 6;
highlighted_days[1].year = 2018;
highlighted_days[1].month = 10;
highlighted_days[1].day = 11;
highlighted_days[2].year = 2018;
highlighted_days[2].month = 11;
highlighted_days[2].day = 22;
lv_calendar_set_highlighted_dates(calendar, highlighted_days, 3);
}
static lv_obj_t * kb;
static lv_obj_t * ta;
static void kb_event_cb(lv_obj_t * keyboard, lv_event_t e)
{
lv_keyboard_def_event_cb(kb, e);
if(e == LV_EVENT_CANCEL) {
lv_keyboard_set_textarea(kb, NULL);
lv_obj_del(kb);
kb = NULL;
}
}
static void kb_create(void)
{
kb = lv_keyboard_create(lv_scr_act(), NULL);
lv_keyboard_set_cursor_manage(kb, true);
lv_obj_set_event_cb(kb, kb_event_cb);
lv_keyboard_set_textarea(kb, ta);
}
static void ta_event_cb(lv_obj_t * ta_local, lv_event_t e)
{
if(e == LV_EVENT_CLICKED && kb == NULL) {
kb_create();
}
}
void lv_ex_keyboard_1(void)
{
/*Create a text area. The keyboard will write here*/
ta = lv_textarea_create(lv_scr_act(), NULL);
lv_obj_align(ta, NULL, LV_ALIGN_IN_TOP_MID, 0, LV_DPI / 16);
lv_obj_set_event_cb(ta, ta_event_cb);
lv_textarea_set_text(ta, "");
lv_coord_t max_h = LV_VER_RES / 2 - LV_DPI / 8;
if(lv_obj_get_height(ta) > max_h) lv_obj_set_height(ta, max_h);
kb_create();
}
void lvGuiStartExample(void)
{
TAL_PR_DEBUG("lvgl example1 start");
if (!lvGuiInit(lv_ex_keyboard_1)) {
TAL_PR_DEBUG("lvGuiInit failed");
}
}
7、增加TUYA 应用启动代码
Code: Select all
/**
* @file ty_lvgl_app.c
* @brief
* @version 0.1
* @date 2023-03-06
*
* @copyright Copyright (c) 2023-2023 Tuya Inc. All Rights Reserved.
*
* Permission is hereby granted, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), Under the premise of complying
* with the license of the third-party open source software contained in the software,
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software.
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
*/
#include "tal_log.h"
#include "tal_thread.h"
#include "tal_system.h"
#include "tal_cellular_vbat.h"
#include "tal_sleep.h"
#include "tkl_cellular_base.h"
#include "oc_app_entry.h"
#include "tal_cellular_mds.h"
#define USR_APP_NAME "TY_LVGL"
#define USR_APP_VER "1.0.0"
THREAD_HANDLE helloTaskHandle = NULL;
/**
* @brief Hello 线程
*
* @param
*
* @return
*/
static void hello_thread(void* arg)
{
int cnt = 0;
OPERATE_RET ret;
// 关闭UART1作为AT口
tkl_cellular_base_ioctl(CELL_IOCTL_SET_ATUART_OFF,NULL);
// 设置用户固件的名称和版本号,涂鸦产测必须设置
tuya_cniot_set_mftest_fw_info(USR_APP_NAME,USR_APP_VER);
// 启动涂鸦产测。
tuya_cniot_start_mftest();
lvGuiStartExample();
while (cnt++ < 10) {
/* 延时1秒 */
lvGuiScreenOn();
TAL_PR_NOTICE("[APPDEMO]: GUI light on");
tal_system_sleep(10000);
lvGuiScreenOff();
TAL_PR_NOTICE("[APPDEMO]: GUI light off");
tal_system_sleep(10000);
}
/* 线程执行完毕,退出 */
ret = tal_thread_delete(helloTaskHandle);
if (OPRT_OK != ret) {
TAL_PR_ERR("[APPDEMO]: hello task exit failed: %d", ret);
} else {
TAL_PR_NOTICE("[APPDEMO]: hello task exit success");
}
}
/**
* @brief 应用入口函数
*
* @return 0 成功
*
* @note 应用必须对其进行实现,系统加载完成后会调用该接口注册应用函数
*/
int appimg_enter(void *param)
{
THREAD_CFG_T cfg;
OPERATE_RET ret;
tuya_cniot_init();
tal_cellular_mds_init(0);
tuya_cniot_start_tuyaos();
TAL_PR_NOTICE("[APPDEMO]: init system success");
// 关闭低电压关机功能,用户根据硬件选择。系统默认开启,用户外部可以关闭
tal_cellular_vbat_low_volt_poweroff_enable(FALSE);
tal_cpu_set_lp_mode(TRUE);
/* 创建 hello 线程 */
cfg.priority = THREAD_PRIO_2;
cfg.stackDepth = 1024 * 8;
cfg.thrdname = "hello";
ret = tal_thread_create_and_start(&helloTaskHandle, NULL, NULL,
hello_thread, NULL, &cfg);
if (OPRT_OK != ret) {
TAL_PR_ERR("[APPDEMO]: create hello task failed: %d", ret);
return -1;
} else {
TAL_PR_NOTICE("[APPDEMO]: create hello task success");
}
return 0;
}
/**
* @brief 完成应用函数注册的打印
*
* @return 无
*
* @note 上层应用函数退出后系统调用该函数打印log
*/
void appimg_exit(void)
{
TAL_PR_NOTICE("[APPDEMO]: application image exit");
}
8、应用编译脚本CMakelists.txt
Code: Select all
# Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA").
# All rights reserved.
#
# This software is supplied "AS IS" without any warranties.
# RDA assumes no responsibility or liability for the use of the software,
# conveys no license or title under any patent, copyright, or mask work
# right to the product. RDA reserves the right to make changes in the
# software without notification. RDA also make no representation or
# warranty that such application will be suitable for the specified use
# without further testing or modification.
cmake_minimum_required(VERSION 3.13)
set(SOURCE_TOP_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(BINARY_TOP_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(PROJECT_ROOT_DIR ${SOURCE_TOP_DIR}/../..)
set(CMAKE_C_COMPILER_FORCED 1)
set(CMAKE_CXX_COMPILER_FORCED 1)
set(out_hex_dir ${CMAKE_CURRENT_BINARY_DIR}/hex)
set(out_lib_dir ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(out_inc_dir ${CMAKE_CURRENT_BINARY_DIR}/include)
set(tools_dir ${PROJECT_ROOT_DIR}/tools)
set(core_stub_o ${PROJECT_ROOT_DIR}/components/lib/core_stub.o)
set(flash_ldscript ${PROJECT_ROOT_DIR}/ldscripts/app_flashimg.ld)
set(cmd_mkappimg dtools mkappimg)
set(pacgen_py ${tools_dir}/pacgen.py)
include(${PROJECT_ROOT_DIR}/cmake/core_config.cmake)
include(${PROJECT_ROOT_DIR}/cmake/toolchain-gcc.cmake)
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${out_lib_dir})
set(libtuyaos_file_name ${PROJECT_ROOT_DIR}/libs/libtuyaos.a)
project(${APP_NAME} C CXX ASM)
function(include_subdirectories root_dir)
if(IS_DIRECTORY ${root_dir})
include_directories(${root_dir})
endif()
file(GLOB ALL_SUB RELATIVE ${root_dir} ${root_dir}/*)
foreach(sub ${ALL_SUB})
if(IS_DIRECTORY ${root_dir}/${sub})
if(NOT (".git" MATCHES ${sub} OR "output" MATCHES ${sub}))
include_subdirectories(${root_dir}/${sub})
endif()
endif()
endforeach()
endfunction()
include_directories(${PROJECT_ROOT_DIR}/components/include)
include_directories(${PROJECT_ROOT_DIR}/components/newlib/include)
include_directories(${SOURCE_TOP_DIR}/include)
include_subdirectories(${PROJECT_ROOT_DIR}/include)
function(cpp_only target file)
add_library(${target} OBJECT ${file})
set_source_files_properties(${file} PROPERTIES LANGUAGE C)
target_compile_options(${target} PRIVATE -E -P -x c)
endfunction()
function(add_appimg target ldscript)
set(gen_ldscript ${target}_ldscript)
set(target_map_file ${out_hex_dir}/${target}.map)
set(target_img_file ${out_hex_dir}/${target}.img)
cpp_only(${gen_ldscript} ${ldscript})
add_executable(${target} ${ARGN} ${core_stub_o})
set_target_properties(${target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${out_hex_dir})
target_link_libraries(${target} PRIVATE -T $<TARGET_OBJECTS:${gen_ldscript}>)
target_link_libraries(${target} PRIVATE -Wl,-Map=${target_map_file} -nostdlib -Wl,--gc-sections)
add_custom_command(TARGET ${target} POST_BUILD
COMMAND ${cmd_mkappimg} $<TARGET_FILE:${target}> ${target_img_file}
BYPRODUCTS ${target_img_file} ${target_map_file}
)
endfunction()
configure_file(${PROJECT_ROOT_DIR}/components/lib/fdl1.img ${out_hex_dir}/fdl1.img COPYONLY)
configure_file(${PROJECT_ROOT_DIR}/components/lib/fdl2.img ${out_hex_dir}/fdl2.img COPYONLY)
macro(pac_init_fdl cmd)
set(${cmd}
cfg-init --pname UIX8910_MODEM --palias "APPIMG"
--pversion "8910 MODULE" --version "BP_R1.0.0"
--flashtype 1
cfg-host-fdl -a ${CONFIG_FDL1_IMAGE_START} -s ${CONFIG_FDL1_IMAGE_SIZE}
-p ${out_hex_dir}/fdl1.img
cfg-fdl2 -a ${CONFIG_FDL2_IMAGE_START} -s ${CONFIG_FDL2_IMAGE_SIZE}
-p ${out_hex_dir}/fdl2.img
)
endmacro()
if(CONFIG_APPIMG_LOAD_FLASH)
set(target appimg_flash_delete)
set(pac_file ${out_hex_dir}/${target}.pac)
pac_init_fdl(init_fdl)
add_custom_command(OUTPUT ${pac_file}
COMMAND python3 ${pacgen_py} ${init_fdl}
cfg-erase-flash -i ERASE_APPIMG
-a ${CONFIG_APPIMG_FLASH_ADDRESS}
-s ${CONFIG_APPIMG_FLASH_SIZE}
pac-gen ${pac_file}
DEPENDS ${pacgen_py}
WORKING_DIRECTORY ${PROJECT_ROOT_DIR}
)
add_custom_target(${target}_pacgen ALL DEPENDS ${pac_file})
endif()
file(READ components.mk CFG_COMPONENTS)
string(REPLACE "COMPONENTS:=" "" COMPONENT_LIST ${CFG_COMPONENTS})
string(REPLACE " " ";" APP_COMPONENTS ${COMPONENT_LIST})
function(add_components_lib dir)
if(EXISTS ${dir})
set(tuya_app_component_path ${dir})
foreach(sub ${APP_COMPONENTS})
if(EXISTS ${tuya_app_component_path}/${sub})
include_subdirectories(${tuya_app_component_path}/${sub}/include)
file(GLOB_RECURSE list_components_files ${tuya_app_component_path}/${sub}/src/*.c)
ADD_LIBRARY(${sub} STATIC ${list_components_files})
endif()
endforeach()
endif()
endfunction()
function(link_components_lib target dir)
if(EXISTS ${dir})
foreach(sub ${APP_COMPONENTS})
if(EXISTS ${dir}/${sub})
message("link_components_lib:${sub}")
target_link_libraries(${target} PRIVATE ${sub})
endif()
endforeach()
endif()
endfunction()
if(CONFIG_APPIMG_LOAD_FLASH)
add_compile_options(-DAPP_NAME="${APP_NAME}" -DAPP_VERSION="${APP_VERSION}")
set(target ${APP_NAME}_${APP_VERSION})
add_appimg(${target} ${flash_ldscript} src/ty_lvgl_app.c src/lv_gui_example.c)
if(APP_COMPONENTS)
message("APP_COMPONENTS:${APP_COMPONENTS}")
add_components_lib(${PROJECT_ROOT_DIR}/components)
add_components_lib(${PROJECT_ROOT_DIR}/application_components)
link_components_lib(${target} ${PROJECT_ROOT_DIR}/components)
link_components_lib(${target} ${PROJECT_ROOT_DIR}/application_components)
endif()
ADD_SUBDIRECTORY(littlevgl build)
target_link_libraries(${target} PRIVATE lvgl)
target_link_libraries(${target} PRIVATE ${libtuyaos_file_name} ${libm_file_name} ${libc_file_name} ${libgcc_file_name})
set(pac_file ${out_hex_dir}/${target}.pac)
set(target_img_file ${out_hex_dir}/${target}.img)
pac_init_fdl(init_fdl)
add_custom_command(OUTPUT ${pac_file}
COMMAND python3 ${pacgen_py} ${init_fdl}
cfg-image -i APPIMG -a ${CONFIG_APPIMG_FLASH_ADDRESS}
-s ${CONFIG_APPIMG_FLASH_SIZE}
-p ${target_img_file}
pac-gen ${pac_file}
DEPENDS ${pacgen_py} ${target_img_file}
WORKING_DIRECTORY ${PROJECT_ROOT_DIR}
)
add_custom_target(${target}_pacgen ALL DEPENDS ${pac_file})
endif()
9、调用build_app.sh 编译应用代码