7.19. 资源区配置(RES和预留区)

Overview

资源区为用户存放资源文件的区域,其中分为两个区域:RES区域和预留区(RESERVED) (FLASH的区域分布请参考: UPDATE ).

  • RES区:res资源区为app code中的一部分,在flash空间允许的范围内,res资源区大小没有限制。在双备份升级中,res资源区也会进行双备份处理,因此res资源在flash中会占用两倍的空间。

  • 预留区: 预留区为独立于app code的一个区域,是客户可以自行配置和使用的区域,即系统会根据客户的配置文件在flash中预留出对应的空间大小由客户自行操作。

7.19.1. RES资源区配置

  • 添加res区资源目录:

修改脚本文件 ``download.c``,在“-res” 选项增加资源目录,如:添加资源目录audlogo

isd_download.exe isd_config.ini -tonorflash -dev wl82 -boot 0x1c02000 -div1 -wait 300 -uboot uboot.boot
-app app.bin cfg_tool.bin -res cfg audlogo source %AUDIO_RES% %UI_RES% %CFG_FILE%
  • 添加资源文件

只需要在已添加的资源目录中加入资源文件,如audlogo目录中增加提示音
  • 资源文件读取

可以通过文件系统接口fread对res区资源进行读取,其路径格式为:mnt/sdfile/res/$(user_dir)/$(filename);
其中user_dir为用户自定义资源目录,filename为用户添加的资

    char name[128];
    char read_buf[BUF_SIZE];
    FILE *f = fopen("mnt/sdfile/res/audlogo/test.mp3", "r");
    if (!f) {
        printf("fopen err!\n")
    }else{
        fget_name(f, name, sizeof(name));
        printf("file_name: %s\n", name);

        int len = fread(read_buf, 1, sizeof(read_buf), f);
        if(len > 0)
        {
            put_buf(read_buf, sizeof(read_buf));
        }
    }

7.19.2. 预留区配置

  • 预留区配置

修改配置文件cpu/wl82/tools/isd_config_rule.c,[RESERVED_EXPAND_CONFIG]或[RESERVED_EXPAND_CONFIG]下添加配置项

注:具体配置说明请参考 doc/stuff/ISD_CONFIG.INI配置文件说明.pdf ,如:


#预留区扩展
[RESERVED_EXPAND_CONFIG]
fixed.mp3_FILE=fixed_res/fixed.mp3;             #fixed_res目录下存放fixed.mp3文件
fixed.mp3_ADR=AUTO;                                             #由工具自动分配起始地址
fixed.mp3_LEN=0x4000;                                   #fixed.mp3文件的大小,需要4K对齐
fixed.mp3_OPT=1;                                                #0:下载代码时擦除指定区域;1:下载代码时不操作指定区域;2:下载代码时给指定区域加上保护;

或
#预留区扩展
[RESERVED_CONFIG]
fixed.mp3_FILE=fixed_res/fixed.mp3;             #fixed_res目录下存放fixed.mp3文件
fixed.mp3_ADR=AUTO;                                             #由工具自动分配起始地址
fixed.mp3_LEN=0x4000;                                   #fixed.mp3文件的大小,需要4K对齐
fixed.mp3_OPT=1;                                                #0:下载代码时擦除指定区域;1:下载代码时不操作指定区域;2:下载代码时给指定区域加上保护;
  • 预留区路径格式

(1)[RESERVED_EXPAND_CONFIG]预留区使用方法可以通过文件系统接口fread对预留区数据进行读取,其路径格式为:mnt/sdfile/EXT_RESERVED/XXX(其中XXX为预留区文件名),如:
    char name[128];
    char read_buf[BUF_SIZE];
    FILE *f = fopen("mnt/sdfile/EXT_RESERVED/fixed.mp3", "r");
    if (!f) {
        printf("fopen err!\n")
    }else{
        fget_name(f, name, sizeof(name));
        printf("file_name: %s\n", name);
            int len = fread(read_buf, 1, sizeof(read_buf), f);
        if(len > 0)
        {
            put_buf(read_buf, sizeof(read_buf));
        }
    }

(2)[RESERVED_CONFIG]预留区使用方法可以通过文件系统接口fread对预留区数据进行读取,其路径格式为:mnt/sdfile/app/XXX(其中XXX为预留区文件名),如:
    char name[128];
    char read_buf[BUF_SIZE];
    FILE *f = fopen("mnt/sdfile/app/fixed.mp3", "r");
    if (!f) {
        printf("fopen err!\n")
    }else{
        fget_name(f, name, sizeof(name));
        printf("file_name: %s\n", name);
        int len = fread(read_buf, 1, sizeof(read_buf), f);
        if(len > 0)
        {
            put_buf(read_buf, sizeof(read_buf));
        }
    }
  • 预留区读写操作:可以通过fread来读取数据,但是不能使用fwrite接口来写入数据。一般采用Flash接口来对预留区进行操作,示例如下:

#include "app_config.h"
#include "system/includes.h"
#include "fs/fs.h"
#include "asm/sfc_norflash_api.h"

#define USER_FLASH_SPACE_PATH "mnt/sdfile/app/exif"

static u32 user_get_flash_exif_addr(void)
{
    u32 addr;

    //打开预留区
    FILE *profile_fp = fopen(USER_FLASH_SPACE_PATH, "r");
    if (profile_fp == NULL) {
        puts("user_get_flash_addr ERROR!!!\r\n");
        return 0;
    }

    struct vfs_attr file_attr;
    fget_attrs(profile_fp, &file_attr);

    //获取预留区的flash地址
    addr = sdfile_cpu_addr2flash_addr(file_attr.sclust);
    fclose(profile_fp);

    printf("user_get_flash_exif_addr = 0x%x, size = 0x%x \r\n", addr,file_attr.fsize);
    return addr;
}

static int c_main(void)
{
    printf("\r\n\r\n\r\n\r\n\r\n ----------- USER_FLASH_EXIF example run %s-------------\r\n\r\n\r\n\r\n\r\n", __TIME__);

    char buf[256];
    u32 flash_exif_addr = user_get_flash_exif_addr();
    if(flash_exif_addr==0)
        return -1;

    //擦除一个扇区
    puts("USER_FLASH_EXIF ERASE_SECTOR...\r\n");
    norflash_ioctl(NULL, IOCTL_ERASE_SECTOR, flash_exif_addr);

    puts("USER_FLASH_EXIF READ\r\n");
    memset(buf,0,sizeof(buf));

    //读取预留区数据
    norflash_read(NULL, buf, sizeof(buf), flash_exif_addr);
    put_buf(buf,sizeof(buf));

    puts("\r\n USER_FLASH_EXIF WRITE\r\n");
    for(int i=0;i<sizeof(buf);i++)
        buf[i] = i;

    //写入数据
    norflash_write(NULL, buf, sizeof(buf), flash_exif_addr);

    puts("USER_FLASH_EXIF READ\r\n");
    memset(buf,0,sizeof(buf));

    //再次读出来,查看数据是否写入成功
    norflash_read(NULL, buf, sizeof(buf), flash_exif_addr);
    put_buf(buf,sizeof(buf));

    return 0;
}
late_initcall(c_main);

7.19.3. 文件打包工具使用

打包工具位于 cpu\wl82\tools\packres, 打开packrec.bat文件, 按照说明添加需要打包的文件,如:

REM packres.exe -n $(dir) -o $(output) $(file1) $(file2) ...
REM 其中$(dir)为打包后的文件目录入口,$(output)打包后的输出文件,$(file1) $(file2) ...为需要打包的输入文件
REM 放置在res资源区时,其搜索路径为mnt/sdfile/res/$(output)/$(dir)/$(file),如:mnt/sdfile/res/tone/res1.txt
REM 放置在[RESERVED_CONFIG]预留区时,其搜索路径为:mnt/sdfile/app/$(output)/$(dir)/$(file),如:mnt/sdfile/app/update/tone/res1.txt
REM 放置在[RESERVED_EXPAND_CONFIG]预留区时,其搜索路径为:mnt/sdfile/EXT_RESERVED/$(output)/$(dir)/$(file),如:mnt/sdfile/EXT_RESERVED/update/tone/res1.txt
packres.exe -n tone -o UPDATE res1.txt res2.txt res3.txt
::pause

7.19.4. 资源文件打包放在预留区或者扩展预留区

若资源区使用双备份升级时,会占用flash两倍的资源空间,为了节省双备份升级时的固件空间,现支持统一把提示音和UI资源统一放在预留区或者扩展预留区, 资源升级采用的是断点可恢复升级的单备份升级方法(若放在扩展预留区,需要在应用层上由客户手动强制升级,一般来说放在扩展预留区的资源是不升级的)。

  • 资源打包放在预留区的配置

//app_config.h配置对应的宏
#if defined CONFIG_UI_ENABLE && !defined CONFIG_SDFILE_EXT_ENABLE
#define CONFIG_UI_FILE_SAVE_IN_RESERVED_ZONE  //UI资源打包后放在预留区,可以通过升级预留区更新此资源,一般用于双备份时UI资源小于代码大小的方案
#endif
#if defined CONFIG_AUDIO_ENABLE && !defined CONFIG_SDFILE_EXT_ENABLE
#define CONFIG_VOICE_PROMPT_FILE_SAVE_IN_RESERVED_ZONE  //提示音资源打包后放在预留区,可以通过升级预留区更新此资源,一般用于双备份时提示音资源小于代码大小的方案
#endif

//在代码编译前,需要根据实际打包后的资源文件空间大小填写tools/isd_config_rule.c里相应的flash空间区域配置
[RESERVED_CONFIG]
//#升级之后需要保留VM数据,在生成升级文件时需要设置VM_OPT=1
VM_ADR=0; [设置VM]
VM_LEN=32K;
#if CONFIG_DOUBLE_BANK_ENABLE
VM_OPT=0;
#else
VM_OPT=1;//单备份升级VM在升级时候默认VM不需要擦除,选择擦除会在ota_loader第二阶段擦除比较长,而且可能会造成VM丢失
#endif

BTIF_ADR=AUTO; [设置资源]
BTIF_LEN=0x1000;
BTIF_OPT=1;

#if defined CONFIG_AUDIO_ENABLE && defined CONFIG_VOICE_PROMPT_FILE_SAVE_IN_RESERVED_ZONE
AUPACKRES_FILE=packres/AUPACKRES; [打包后的资源文件的相对路径]
AUPACKRES_ADR=0xXXXXXX; [请根据编译后FLASH INFO打印的实际地址填写,比如0x59a000,烧录后不支持升级更改]
AUPACKRES_LEN=0xXXXXXX; [更新提示音资源打包后必须更新此实际长度,比如0x141000,建议根据后续资源升级的需求预留好足够的空间,烧录后不支持升级更改]
AUPACKRES_OPT=1;
#endif

#if defined CONFIG_UI_ENABLE && defined CONFIG_UI_FILE_SAVE_IN_RESERVED_ZONE
UIPACKRES_FILE=packres/UIPACKRES;
UIPACKRES_ADR=0xXXXXXX; [请根据编译后FLASH INFO打印的实际地址填写,比如0x6db000,烧录后不支持升级更改]
UIPACKRES_LEN=0xXXXXXX; [更新UI资源打包后必须更新此实际长度,比如0x123000, 建议根据后续资源升级的需求预留好足够的空间,烧录后不支持升级更改]
UIPACKRES_OPT=1;
#endif

PRCT_ADR=0;
PRCT_LEN=CODE_LEN;
PRCT_OPT=2;
  • 资源打包放在扩展预留区的配置

//app_config.h配置对应的宏
#if defined CONFIG_UI_ENABLE && !defined CONFIG_SDFILE_EXT_ENABLE
#define CONFIG_UI_FILE_SAVE_IN_RESERVED_EXPAND_ZONE  //UI资源打包后放在扩展预留区,不可以通过常规升级更新此资源,一般用于UI不需要更新的方案
#endif
#if defined CONFIG_AUDIO_ENABLE && !defined CONFIG_SDFILE_EXT_ENABLE
#define CONFIG_VOICE_PROMPT_FILE_SAVE_IN_RESERVED_EXPAND_ZONE  //提示音资源打包后放在扩展预留区,不可以通过常规升级更新此资源,一般用于提示音不需要更新的方案
#endif

//在代码编译前,需要根据实际打包后的资源文件空间大小填写tools/isd_config_rule.c里相应的flash空间区域配置
[RESERVED_EXPAND_CONFIG]
USER_ADR=AUTO; [固定预留给客户,避免客户量产后,想通过升级新增重要信息的保存却没有预先预留空间]
USER_LEN=0x1000;
USER_OPT=1;

//packers文件夹下会生成AUPACKRES,UIPACKRES这两个包是资源文件打包好的包需要
//根据实际大小填写AUPACKRES_ADR,AUPACKRES_LEN,
//AUPACKRES_ADR 配置 AUTO 第一次下载后会下载不进 需要根据FLASH INFO打印的实际地址填写
//例如AUPACKRES 378KB = 0x5e800 实际填大小可以填大一些 AUPACKRES_LEN = 0x5f000
#if defined CONFIG_AUDIO_ENABLE && defined CONFIG_VOICE_PROMPT_FILE_SAVE_IN_RESERVED_EXPAND_ZONE
AUPACKRES_FILE=packres/AUPACKRES; [烧录后不可升级的资源]
AUPACKRES_ADR=0xXXXXXX; [请根据编译后FLASH INFO打印的实际地址填写,比如0x59b000,建议预留好足够的空间,烧录后不支持升级更改]
AUPACKRES_LEN=0xXXXXXX; [更新提示音资源打包后必须更新此实际长度,比如0x141000,,建议预留好足够的空间,烧录后不支持升级更改]
AUPACKRES_OPT=1;
#endif

#if defined CONFIG_UI_ENABLE && defined CONFIG_UI_FILE_SAVE_IN_RESERVED_EXPAND_ZONE
UIPACKRES_FILE=packres/UIPACKRES; [烧录后不可升级的资源]
UIPACKRES_ADR=0xXXXXXX; [请根据编译后FLASH INFO打印的实际地址填写,比如0x6dc000,建议预留好足够的空间,烧录后不支持升级更改]
UIPACKRES_LEN=0xXXXXXX; [更新UI资源打包后必须更新此实际长度,比如0x123000,建议预留好足够的空间,烧录后不支持升级更改]
UIPACKRES_OPT=1;
#endif
  • 非常规方法升级扩展预留区资源

//因为扩展预留区不能通过常规的OTA升级更新,需要用户在应用层自行获取升级资源后,直接通过flash擦写的方法去更新扩展预留区资源,具体参考apps/common/update/expand_zone_file_update.c
//测试时需要修改isd_config.ini文件把UIPACKRES_LEN设置成AUPACKRES_LEN同一个值
static int expand_zone_packres_file_test(void)
{
    u32 au_update_addr, ui_update_addr;
    void *data = malloc(SDFILE_SECTOR_SIZE);

    check_expand_zone_packres_file_crc("mnt/sdfile/EXT_RESERVED/aupackres");
    check_expand_zone_packres_file_crc("mnt/sdfile/EXT_RESERVED/uipackres");

    au_update_addr = expand_zone_packres_file_update_start("mnt/sdfile/EXT_RESERVED/aupackres");
    ui_update_addr = expand_zone_packres_file_update_start("mnt/sdfile/EXT_RESERVED/uipackres");

    for (u32 offset = 0; offset < 0x141000; offset += SDFILE_SECTOR_SIZE) {
        sdfile_reserve_zone_read(data, au_update_addr + offset, SDFILE_SECTOR_SIZE, 0);
        //把UI资源擦写成提示音资源
        expand_zone_packres_file_update_write(ui_update_addr + offset, data, SDFILE_SECTOR_SIZE);
    }

    free(data);

    //升级完成后重新校验文件完整性
    check_expand_zone_packres_file_crc("mnt/sdfile/EXT_RESERVED/aupackres");
    check_expand_zone_packres_file_crc("mnt/sdfile/EXT_RESERVED/uipackres");

    return 0;
}

7.19.5. 常见问题

(1) [RESERVED_CONFIG]与[RESERVED_EXPAND_CONFIG]的区别?

答:[RESERVED_CONFIG] 区域最多可以设置6个配置项,其中VM、BTIF和PRCT为系统默认使用,用户不能占用。 用户可使用的只有3个配置项(如:配置文件中PROFILE、AISP和EXIF),可以根据实际需要进行使用和修改。当超出使用个数时,可以使用 [RESERVED_EXPAND_CONFIG] 区域。 当使用预留区作为资源升级区时,只能使用 [RESERVED_CONFIG][RESERVED_EXPAND_CONFIG] 区域暂时不支持作为资源升级区使用。 [RESERVED_EXPAND_CONFIG] 区域在flash空间足够的情况下没有个数限制。

(2) 预留区中指定文件,但是没有填写绝对地址导致编译器报错问题,如“错误:在配置文件(isd_config.ini)中发现非标准的预留区域配置。”?

答:当预留区指定文件时,只有编译后才知道工具实际给文件分配的地址,因此需要对isd_config_rule.c 文件进行修改。如上图:在FLASH INFO中获知AUPACKRES_RESERVED_SIZE : 0x141000, AUPACKRES_RESERVED_START : 0x6bd000,在isd_config_rule.c修改AUPACKRES_ADR=0x6bd000, AUPACKRES_LEN=0x141000。再编译工程即可。