Keil编译后自动添加版本号且自动合并bootloader

一、将版本号放在代码固定的地方

/* 将版本号转化为int类型,保存在.bin偏移0x1000处 */
#define APP_VERSION_ADDR (APP_FLASH_START_ADDR + 0x1000)
#define VERSION_MAKE(vh, vm, vl) ((vh << 16) | (vm << 8) | vl)
static const uint32_t version __attribute__((at(APP_VERSION_ADDR))) = VERSION_MAKE(1, 1, 2);

二、编写程序读取编译后的.bin文件,并读取到版本号

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include "stdio.h"
#include "stdint.h"
#include "string.h"

void show_usage()
{
    printf("usage: rename_bin -i \"xxx.bin\" -a \"xxxx\"");
    printf("\r\n");
    printf("\t-i bin_file"
           "\t\t input file\r\n");
    printf("\t-a"
           "\t\t version store addr offset \r\n");
    printf("\r\n");
}

int main(int argc, char *argv[])
{
    char file_name[128] = {0};
    char file_name_with_version[128] = {0};
    uint32_t addr = 0;
    uint8_t vh = 0;
    uint8_t vm = 0;
    uint8_t vl = 0;
    char version[128] = {0};
    int fd = 0;

    // test
    remove("FILENAME_WITH_VERSION.txt");

    if (argc != 5)
    {
        show_usage();
        return 0;
    }

    /* parase input file */
    if (memcmp(argv[1], "-i", strlen("-i")) != 0)
    {
        printf("please use -i to add input file\r\n");
        show_usage();
        return 0;
    }
    else if (strncmp(argv[2] + (strlen(argv[2]) - strlen(".bin")), ".bin", strlen(".bin") != 0))
    {
        printf("the input file is not a bin file\r\n");
        show_usage();
        return 0;
    }
    strncpy(file_name, argv[2], 128);

    /* parase offset addr */
    if (memcmp(argv[3], "-a", strlen("-a")) != 0)
    {
        printf("please use -a to add offset addr\r\n");
        show_usage();
        return 0;
    }
    sscanf(argv[4], "%x", &addr);
    printf("offset addr is %x\r\n", addr);

    /* open in file */
    fd = open(file_name, O_RDWR | O_BINARY);
    if (fd <= 0)
    {
        printf("cant open file %s, line %d\r\n", file_name, __LINE__);
        return 0;
    }

    lseek(fd, addr, SEEK_SET); // set to version byte

    read(fd, &vl, 1);
    read(fd, &vm, 1);
    read(fd, &vh, 1);

    close(fd);
    strncpy(file_name_with_version, file_name, strlen(file_name) - strlen(".bin"));
    snprintf(version, 128, "V%d.%d.%d", vh, vm, vl);
    strcat(file_name_with_version, "_");
    strcat(file_name_with_version, version);
    strcat(file_name_with_version, ".bin");

    printf("rename file name %s to %s\r\n", file_name, file_name_with_version);
    remove(file_name_with_version);
    rename(file_name, file_name_with_version);

    // 将文件名输出到FILENAME_WITH_VERSION.txt文件中,方便外部引用
    int fd_file_name_with_version = -1;
    fd_file_name_with_version = open("FILENAME_WITH_VERSION.txt", O_CREAT | O_RDWR | O_TRUNC | O_TEXT, 0777);
    if (fd_file_name_with_version > 0)
    {
        printf("create FILENAME_WITH_VERSION.txt\r\n");
        write(fd_file_name_with_version, file_name_with_version, strlen(file_name_with_version));
        close(fd_file_name_with_version);
    }

    return 0;
}

编译以上代码为FilenameAddVersion.c.exe

三、编译后自动合并bootloader和App

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "stdio.h"
#include "stdint.h"
#include "string.h"

uint8_t check_sum_add8(uint8_t *data_buf, uint8_t len)
{
    uint8_t sum = 0;
    for (uint32_t i = 0; i < len; i++)
    {
        sum += data_buf[i];
    }
    return (0x100 - sum);
}

// HEX格式:|:1|长度2|地址2|数据类型1|数据长度32|校验和1|
int32_t output_hexline_to_file(uint32_t fd, uint32_t addr, uint8_t *date_buf, uint32_t date_len, uint8_t data_type)
{
    uint32_t i = 0;
    uint8_t hex_buf[128] = {0};
    char hex_file_buf[8] = {0};
    uint8_t hex_len = 0;

    hex_buf[0] = date_len;
    switch (data_type)
    {
    case 0x00: /* 用来记录数据, HEX文件的大部分记录都是数据记录*/
        hex_buf[1] = (addr >> 8) & 0xFF;
        hex_buf[2] = addr & 0xFF;
        hex_buf[3] = 0x00;
        for (i = 0; i < date_len; i++)
        {
            hex_buf[4 + i] = date_buf[i];
        }
        hex_buf[4 + i] = check_sum_add8(hex_buf, 4 + i);
        hex_len = 4 + i + 1;
        break;

    case 0x01: /* 用来标识文件结束,放在文件的最后, 标识HEX文件的结尾*/
        hex_buf[1] = 0x00;
        hex_buf[2] = 0x00;
        hex_buf[3] = 0x01;
        hex_buf[4] = 0xFF;
        hex_len = 4 + 1;
        break;

    case 0x02: /* 用来标识扩展段地址的记录*/
        break;

    case 0x03: /* 开始段地址记录*/
        break;

    case 0x04: /* 用来标识扩展线性地址的记录*/
        hex_buf[1] = 0x00;
        hex_buf[2] = 0x00;
        hex_buf[3] = 0x04;

        hex_buf[4] = date_buf[1];
        hex_buf[5] = date_buf[0];

        hex_buf[6] = check_sum_add8(hex_buf, 6);
        hex_len = 7;
        break;

    case 0x05: /* 开始线性地址记录*/
        break;

    default:
        break;
    }

    write(fd, ":", 1);
    for (i = 0; i < hex_len; i++)
    {
        sprintf(hex_file_buf, "%02X", hex_buf[i]);
        write(fd, hex_file_buf, 2);
    }
    write(fd, "\n", 1);

    return 0;
}

int merage_bootload_app_to_hex(char *bootload_file_name, uint32_t bootload_start_addr,
                               char *app_file_name, uint32_t app_start_addr, char *hex_file_name)
{
    uint32_t cur_hex_addr = 0; // 当前 hex 文件地址
    int32_t bootload_fd = -1;
    int32_t app_fd = -1;
    int32_t hex_fd = -1;
    uint16_t addr_high = 0;
    uint8_t read_num = 0;
    uint8_t read_buf[64] = {0};

    bootload_fd = open(bootload_file_name, O_RDWR | O_BINARY);
    if (bootload_fd < 0)
    {
        printf("Open bootload file failed!\r\n");
        goto __exit;
    }

    app_fd = open(app_file_name, O_RDWR | O_BINARY);
    if (app_fd < 0)
    {
        printf("Open app file failed!\r\n");
        goto __exit;
    }

    hex_fd = open(hex_file_name, O_RDWR | O_CREAT | O_TRUNC);
    if (hex_fd < 0)
    {
        printf("Create merge hex file failed!\r\n");
        goto __exit;
    }

    // 写入Bootload
    cur_hex_addr = bootload_start_addr;
    addr_high = ((cur_hex_addr >> 16) & 0xFFFF);
    output_hexline_to_file(hex_fd, 0, (uint8_t *)&addr_high, 2, 0x04);
    while (1)
    {
        // 更新标识扩展线性地址
        if (((cur_hex_addr >> 16) & 0xFFFF) != addr_high)
        {
            addr_high = ((cur_hex_addr >> 16) & 0xFFFF);
            output_hexline_to_file(hex_fd, 0, (uint8_t *)&addr_high, 2, 0x04);
        }

        read_num = read(bootload_fd, read_buf, 32);
        if (read_num > 0)
        {
            output_hexline_to_file(hex_fd, cur_hex_addr & 0xFFFF, read_buf, read_num, 0x00);
            cur_hex_addr += read_num;
        }
        else
        {
            break;
        }
    }

    // 写入App
    cur_hex_addr = app_start_addr;
    while (1)
    {
        // 更新标识扩展线性地址
        if (((cur_hex_addr >> 16) & 0xFFFF) != addr_high)
        {
            addr_high = ((cur_hex_addr >> 16) & 0xFFFF);
            output_hexline_to_file(hex_fd, 0, (uint8_t *)&addr_high, 2, 0x04);
        }

        read_num = read(app_fd, read_buf, 32);
        if (read_num > 0)
        {
            output_hexline_to_file(hex_fd, cur_hex_addr & 0xFFFF, read_buf, read_num, 0x00);
            cur_hex_addr += read_num;
        }
        else
        {
            output_hexline_to_file(hex_fd, 0, 0, 0, 0x01);
            break;
        }
    }

    printf("Merage %s and %s to %s success!\n", bootload_file_name, app_file_name, hex_file_name);
__exit:
    if (bootload_fd > 0)
    {
        close(bootload_fd);
    }
    if (hex_fd > 0)
    {
        close(hex_fd);
    }

    return 0;
}

void show_usage(void)
{
    printf("usage: MergerBootloadApp2Hex path/bootloader.bin 0x08000000 path/app.bin 0x08010000");
}

int main(int argc, char const *argv[])
{
    char bootload_file_name[512] = {0};
    char app_file_name[512] = {0};
    char hex_file_name[512] = {0};

    uint32_t bootload_start_addr = 0x08000000; // bootload文件地址
    uint32_t app_start_addr = 0x08010000;      // app文件地址

    if (argc < 5)
    {
        show_usage();
        return 0;
    }

    strcpy(bootload_file_name, argv[1]);
    sscanf(argv[2], "%x", &bootload_start_addr);
    strcpy(app_file_name, argv[3]);
    sscanf(argv[4], "%x", &app_start_addr);

    strncpy(hex_file_name, app_file_name, strlen(app_file_name) - strlen(".bin"));
    strcat(hex_file_name, ".hex");

    printf("Bootload(%08X):  %s\r\n", bootload_start_addr, bootload_file_name);
    printf("App(%08X):  %s\r\n", app_start_addr, app_file_name);
    printf("Merge hex:  %s\r\n", hex_file_name);
    merage_bootload_app_to_hex(bootload_file_name, bootload_start_addr, app_file_name, app_start_addr, hex_file_name);
}

编译以上代码为MergerBootloadApp2Hex.exe

四、编写自动执行脚本

set BOOTLOAD_FILENAME=.\bootload.bin
set BOOTLOAD_ADDR=0x08000000
set APP_FILENAME=.\%1.bin
set APP_ADDR=0x08008000
set APP_VERSION_ADDR=0x1000

:: 在bin文件后添加添加版本号
.\tools\FilenameAddVersion.exe -i %APP_FILENAME% -a %APP_VERSION_ADDR%

:: 将bin文件名称读取到FILENAME_WITH_VERSION
@echo off
if not exist "FILENAME_WITH_VERSION.txt" (
	@echo on
    echo FILENAME_WITH_VERSION.txt not exist, return right now!
    exit /b 1
)
@echo on
set /p FILENAME_WITH_VERSION=<FILENAME_WITH_VERSION.txt

:: 将app和bootload合并成一个hex文件
.\tools\MergerBootloadApp2Hex.exe %BOOTLOAD_FILENAME% %BOOTLOAD_ADDR% %FILENAME_WITH_VERSION% %APP_ADDR%

讲以上内容保存为AddVersion&MergeBootload.bat

五、在Keil执行编译后执行脚本

"AddVersion&MergeBootload.bat" @L
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值