关于CAT1上移植LVGL的研究

Lte-Cat.1/Cat.4/Cat.M设备,NB-IoT设备等
Post Reply
东皇007
Posts: 45

在当前的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 编译应用代码

haitun
Posts: 8

Re: 关于CAT1上移植LVGL的研究

牛掰

Post Reply