gd32f103vbt6 串口OTA升级5-combin部分

这篇具有很好参考价值的文章主要介绍了gd32f103vbt6 串口OTA升级5-combin部分。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一. 简介


本文主要是bin文件的组成进行一些简单介绍,方便理解升级的过程。

gd32f103vbt6 串口OTA升级5-combin部分,mongodb,数据库

二.硬件部分


2.1 rk3399cpu+gd32f103

2.2 连接方式:串口(115200,8N1)或者iic(本文没有介绍iic)

三、其他需要说明的软件部分


3.1 单片机端分两个部分:iap(用于升级)和app(自己的应用)部分(这两个部分本文不做介绍)。
3.2 linux端做一个升级的app软件,这里称为update_app,本文主要是介绍该软件。
3.3 升级单片机用的bin文件,由iap的bin与app的bin的一个组合文件。由combin.exe在keil编译时调用完成。(本文不介绍该软件)
3.4 单片机flash的分区情况
3.4.1  0 ~(0x5c00-1) : iap程序区,用于存放iap程序
3.4.2  0x5c00~(0x6000-1) : 这个1k用于存放一些标志位,以及程序的md5
3.4.3  0x6000 ~(0x13000-1): app程序区,单片机的实际功能程序区
3.4.4  0x13000 ~ (0x20000-1) : app程序下载时的缓存区,程序下载时不直接下载到app区,而是先缓存到下载区,下载成功(数据完成后,会进行md5校验)后,才会更新到app区。
 

四、combin程序部分

4.1 main函数,程序需要三个参数

参数1: iap的bin文件名

参数2:app的bin文件名

参数3:合并后的文件名。本来准备设计为可以不要第三个参数的,此时传入NULL,但是没有测试。

int main(int argc,char* argv[])
{
	char* outfilename = NULL;

	if(argc < 3){
		printf("Usage : %s <file1.bin> <file2.bin> [outfilename]\n",argv[0]);
		return -1;
	}

	if(argc >= 4)
	{
		outfilename = argv[3];
	}

	//第一个文件,与第二个文件合并,生成第三个文件,第三个可以不指定。
	combin_file(argv[1],argv[2],outfilename);

	return 0;

}

4.2 主要的combin_file函数

4.2.1 两个bin文件打开后,都进行了头部的识别工作,非bin文件应该不能正常合并。

4.2.2 这里还考虑了通用单片机合并的情况,就是对偏移的值是进行读取,并不是固定值。

4.2.3 我使用的时候都是传入了参数3的,所以如何去组合出输出文件名没有测试,可能功能不正常。这里要考虑的问题是相对路径和绝对路径,取出文件名这些,好像有点复杂。

void combin_file(char* file1,char* file2,char* outfilename)
{
	FILE *fin1,*fin2;// *fout;
    int size1 = 0,size2 = 0,total_size = 0;
    char outnamebuf[64] = {0};
    uint16_t posision = 0;   //位置
    int bw = 0;       
    int readcount = 0;
    int ret,i;
    int lcd_inch = 0;

    if(file1== NULL || file2 == NULL)
    {
    	printf("ERROR : file is NULL \n");
    	return ;
    }

    //1. 这一段是考虑没有指定输出文件名的情况,但是实际效果没有测试,可能有问题。
    //形成输出文件名
    if(outfilename == NULL)
    {
    	size1 = strlen(file1)-4;
    	if(size1 > 29)
    		size1 = 29;

    	size2 = strlen(file2)-4;
    	if(size2 > 29)
    		size2 = 29;
    	strncpy(outnamebuf,file1,size1); //不需要后缀
    	strcat(outnamebuf,"_");  //加入下划线
    	strncat(outnamebuf,file2,size2);
    	strcat(outnamebuf,".bin");
    }
    else
    {
    	size1 = strlen(outfilename);
    	if(size1 > 63)  //文件名太长了
    	{
    		size2 = size1;
    		size1 = 59;
    	}	
    	strncpy(outnamebuf,outfilename,size1);

    	if(size2 > 63)
    	{
    		strcat(outnamebuf,".bin");
    	}
    }	
    printf("outnamebuf = %s\n",outnamebuf);



    //2.得到app文件的md5值,存在全局变量中
    get_file_md5sum(file2);

    //3.打开iap的bin文件,全部读取处理
    fin1 = fopen(file1, "rb");
    if (fin1 != NULL)
    {
        /* 文件打开成功*/
        printf("open %s success\r\n",file1);
    }
    else
    {
        printf("open %s error\r\n",file1);
        return ;
    }

    //4.打开app的bin文件,全部读取处理
    fin2 = fopen(file2, "rb");
    if (fin2 != NULL)
    {
        /* 文件打开成功*/
        printf("open %s success\r\n",file2);
    }
    else
    {
    	fclose(fin1);
        printf("open %s error\r\n",file2);
        return ;
    }

    //5.得到app文件的大小
    fseek(fin2, 0, SEEK_END);
    size2 = ftell(fin2);
    
    //6.得到iap文件的大小
	fseek(fin1, 0, SEEK_END);
    size1 = ftell(fin1);
	fseek(fin1, 0, SEEK_SET); 


    printf("file2 size = %d\r\n", size2);
    total_size = size2+0x6000;  //7.需要分配的空间的大小
    char* buf = malloc(total_size);  //开一个空间
    if(buf == NULL)
    {
    	printf("error: total_size malloc %d\n",total_size);
    	fclose(fin1);
    	fclose(fin2);
    	return ;
    }

    //8.因为flash中没有数据的位置都是0xff,所以把缓存填充0xff
    memset(buf,0xff,total_size);   //先填充0xff

	
	//9.读取appbin文件的内容,先判断前8个字节的内容,是否符合bin文件的特征。
	fseek(fin2, 0, SEEK_SET);
	ret = fread(buf, 1, 8, fin2);   //从app文件中读取4个字节
	if(ret == 8)
	{
		if (((*(uint32_t*)buf) & 0xfFFE0000 ) != 0x20000000)
		{
			printf("image addr 0 != 0x20000000\n");
			printf("ERROR: bad image(app.bin)!!!!! combin cancle!!!,please check bin file!!!");
			fclose(fin1);
    		fclose(fin2);
			free(buf);
			return ;
		}
		else if(((*(uint32_t*)(buf+4)) & 0xfFFf0000 ) != 0x08000000)
		{
			printf("image  addr %#x != ApplicationAddress %#x\n",((*(uint32_t*)(buf+4)) & 0xfFFffc00 ),0x08000000);
			printf("ERROR: bad image(app.bin)!!!!! combin cancle!!!,please check again!!!");
			fclose(fin1);
    		fclose(fin2);
			free(buf);
			return ;
		}

		posision = ((*(uint16_t*)(buf+4)) & 0xfc00 );   //10.关键的一部,bin文件中可以知道app的偏移值,这里考虑的是不同单片机的偏移不同的问题
		printf("posision = %#x\n",posision);
	}
	else
	{
		printf("error: fread(buf, 1, 2, fin2)\n");
        fclose(fin1);
        fclose(fin2);
        free(buf);
		return;
	}

	//11.正常偏移是24k左右,但是综合考虑,选择了2k,怕有的程序的偏移过小。
    if(posision < 2048)
    {
        printf("ERROR: bad app image(bin)!!!!! ,please check app.bin!!!\n");
        fclose(fin1);
        fclose(fin2);
        free(buf);
        return;
    }

	//12. iap的大小超过了整个偏移区的地址
    if(size1 > posision-1024)
	{
		printf("ERROR: bad iap image(bin)!!!!! ,please check iap.bin!!!\n");
		fclose(fin1);
		fclose(fin2);
		free(buf);
	}

	//13.偏移不是24k的情况,调整一下大小
	if(posision <= 0x6000) //
	{
		total_size = total_size - 0x6000 + posision;   //重新调整一下大小
		printf("total_size = %d\n",total_size);
	}
	else
	{
		printf("ERROR: bad app image(bin)!!!!! ,please check app.bin!!!\n");
		fclose(fin1);
        fclose(fin2);
        free(buf);
        return;
	}


	//14.文件2指针还原,指向文件开始的位置
	fseek(fin2, 0, SEEK_SET);

	//15.把iap的bin文件全部读出来
	printf("size1 = %d\n",size1);
	readcount = 0;
	do
    {
        bw = fread(buf+readcount, 1, size1-readcount, fin1);
        if(bw == 0)
        	break;
        readcount += bw;
    } while (readcount < size1);


    //16.判断bin的合法性,
    if (((*(uint32_t*)buf) & 0xfFFE0000 ) != 0x20000000)
	{
		printf("image addr 0 != 0x20000000\n");
		printf("ERROR: bad image(iap.bin)!!!!! combin cancle!!!,please check bin file!!!\n");
		fclose(fin1);
		fclose(fin2);
		free(buf);
		return ;
	}
	else if(((*(uint32_t*)(buf+4)) & 0xfFFffc00 ) != 0x08000000)
	{
		printf("image  addr %#x != ApplicationAddress %#x\n",((*(uint32_t*)(buf+4)) & 0xfFFffc00 ),0x08000000);
		printf("ERROR: bad image(iap.bin)!!!!! combin cancle!!!,please check again!!!\n");
		fclose(fin1);
		fclose(fin2);
		free(buf);
		return ;
	}



    //17.把app的bin文件全部读出来
    printf("size2 = %d\n",size2);
	readcount = posision;  //app的位置,在bin中已经指定
	do
    {
        bw = fread(&buf[readcount], 1, size2, fin2);
        if(bw == 0)
        	break;
        readcount += bw;
    } while (readcount-posision < size2);


    //18,缓存的特定位置加入下载标记,升级标记,文件大小和md5值
    posision -= 0x400;   //退1k字节
    printf("posion2 = %#x\n",posision);
    (*(uint32_t*)(buf+4+posision)) = size2;  //只保存app 的bin文件大小
    (*(uint16_t*)(buf+posision)) = 0xff;     //不需要升级

    //19.这个地方比较特殊,设置对不同屏幕设置不同标记,方便单片机区分屏幕
    if(strstr(file2,"old5") != NULL)
    {
    //    lcd_inch = 4;  
        (*(uint8_t*)(buf+posision-1)) = 5;
        printf("detect old5inch\n"); 
    }
    else if(strstr(file2,"7inch") != NULL)
    {
    //     lcd_inch = 5;  
         (*(uint8_t*)(buf+posision-1)) = 4; 
         printf("detect 7inch\n"); 
    }
    else if(strstr(file2,"new5") != NULL)
    {
    //    lcd_inch = 6;
        (*(uint8_t*)(buf+posision-1)) = 6; 
        printf("detect new5inch\n"); 
    }

    //20,缓存的特定位置md5值,后面以为要区分多个单片机的bin,所以不同的单片机进行了一些小的偏移
    //所以md5的位置也不会是固定的。同一个单片机肯定是固定在某个位置。
    posision += 512;   //写入md5的值。2023-06-12 hj的+8
    if(strstr(file2,"hj22134") != NULL)
        posision += 8; // hj的+8
    printf("posion3 = %#x\n",posision);
    for(i=0;i<32;i++)
    {
    	buf[i+posision] = md5_readBuf[i];
    }

    fclose(fin1);
    fclose(fin2);

    //21.将缓存的内容生成第三个文件
    fin1 = fopen(outnamebuf, "wb");
    if (fin1 != NULL)
    {
        /* 文件打开成功*/
        printf("3.open %s success \n",outnamebuf);
    }
    else
    {
        printf("3.open %s error \n",outnamebuf);
        free(buf);
        return ;
    }

    //22.写入文件
    readcount = 0;
	do
    {
        bw = fwrite(&buf[readcount], 1, total_size, fin1);
        readcount += bw;
    } while (readcount < total_size);

    fclose(fin1);
    free(buf);

    printf("combin complete!! size = %d\n",total_size);

    return;
}

 

五、总结

5.1 组合bin文件应该是一个比较简单的操作,但是说明一下,有助于理解升级过程。

5.2 该程序编译后,生成exe,由keil自动调用生成即可,比较方便。

gd32f103vbt6 串口OTA升级5-combin部分,mongodb,数据库

 点击编译之后,自动就生成好了。

gd32f103vbt6 串口OTA升级5-combin部分,mongodb,数据库

 5.3 全部代码如下:windows下使用mingw64编译即可文章来源地址https://www.toymoban.com/news/detail-601300.html

/*
* @Author: dazhi
* @Date:   2023-05-09 09:30:03
* @Last Modified by:   dazhi
* @Last Modified time: 2023-07-19 14:17:56
*
* 如果使用md5sum的命令,则在windows下编译时,无法计算md值
* 下载mingw64:
* https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/mingw-w64-v11.0.0.zip
* D:\Programfile\mingw64\bin\gcc combin.c -o combin
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include <unistd.h>
#include <string.h>
#include <libgen.h>
//#include "md5.h"

char md5_readBuf[64] = {0};


#if 1  

#define ROTATELEFT(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))

/**
 * @desc: convert message and mes_bkp string into integer array and store them in w
 */
static void md5_process_part1(uint32_t *w, unsigned char *message, uint32_t *pos, uint32_t mes_len, const unsigned char *mes_bkp)
{
    uint32_t i; // used in for loop

    for(i = 0; i <= 15; i++)
    {
        int32_t count = 0;
        while(*pos < mes_len && count <= 24)
        {
            w[i] += (((uint32_t)message[*pos]) << count);
            (*pos)++;
            count += 8;
        }
        while(count <= 24)
        {
            w[i] += (((uint32_t)mes_bkp[*pos - mes_len]) << count);
            (*pos)++;
            count += 8;
        }
    }
}

/**
 * @desc: start encryption based on w
 */
static void md5_process_part2(uint32_t abcd[4], uint32_t *w, const uint32_t k[64], const uint32_t s[64])
{
    uint32_t i; // used in for loop

    uint32_t a = abcd[0];
    uint32_t b = abcd[1];
    uint32_t c = abcd[2];
    uint32_t d = abcd[3];
    uint32_t f = 0;
    uint32_t g = 0;

    for(i = 0; i < 64; i++)
    {
        if(i <= 15) //i >= 0 && 
        {
            f = (b & c) | ((~b) & d);
            g = i;
        }else if(i >= 16 && i <= 31)
        {
            f = (d & b) | ((~d) & c);
            g = (5 * i + 1) % 16;
        }else if(i >= 32 && i <= 47)
        {
            f = b ^ c ^ d;
            g = (3 * i + 5) % 16;
        }else if(i >= 48 && i <= 63)
        {
            f = c ^ (b | (~d));
            g = (7 * i) % 16;
        }
        uint32_t temp = d;
        d = c;
        c = b;
        b = ROTATELEFT((a + f + k[i] + w[g]), s[i]) + b;
        a = temp;
    }

    abcd[0] += a;
    abcd[1] += b;
    abcd[2] += c;
    abcd[3] += d;
}

static const uint32_t k_table[]={
    0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
    0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,
    0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,
    0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,
    0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
    0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,
    0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,
    0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,
    0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
    0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,
    0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,
    0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,
    0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391
};

static const uint32_t s_table[]={
    7,12,17,22,7,12,17,22,7,12,17,22,7,
    12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
    4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,
    15,21,6,10,15,21,6,10,15,21,6,10,15,21
};

int32_t cal_md5(unsigned char *result, unsigned char *data, int length){
    if (result == NULL)
    {
        return 1;
    }

    uint32_t w[16];

    uint32_t i; // used in for loop

    uint32_t mes_len = length;
    uint32_t looptimes = (mes_len + 8) / 64 + 1;
    uint32_t abcd[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476};

    uint32_t pos = 0; // position pointer for message
    uint32_t bkp_len = 64 * looptimes - mes_len; // 经过计算发现不超过72

//    unsigned char *bkp_mes = (unsigned char *)calloc(1, bkp_len);
    unsigned char bkp_mes[80];
    for(int i = 0; i < 80; i++) //初始化
    {
        bkp_mes[i] = 0;
    }

    bkp_mes[0] = (unsigned char)(0x80);
    uint64_t mes_bit_len = ((uint64_t)mes_len) * 8;
    for(i = 0; i < 8; i++)
    {
        bkp_mes[bkp_len-i-1] = (unsigned char)((mes_bit_len & (0x00000000000000FF << (8 * (7 - i)))) >> (8 * (7 - i)));
    }

    for(i = 0; i < looptimes; i++)
    {
        for(int j = 0; j < 16; j++) //初始化
        {
            w[j] = 0x00000000;
        }

        md5_process_part1(w, data, &pos, mes_len, bkp_mes); // compute w

        md5_process_part2(abcd, w, k_table, s_table); // calculate md5 and store the result in abcd
    }

    for(int i = 0; i < 16; i++)
    {
        //result[i] = ((unsigned char*)abcd)[i];
		sprintf((char*)result+i*2,"%02x",((unsigned char*)abcd)[i]);   //2023-05-09 返回字符串
    }

    return 0;
}

#endif



int get_file_md5sum(const char * filename)
{
	FILE * fin1;
//	char cmd[128] = {"md5sum "};
	int size1 ;
	int ret;
	int readcount,bw;

    fin1 = fopen(filename, "rb");
    if (fin1 != NULL)
    {
        /* 文件打开成功*/
        printf("open %s success\r\n",filename);
    }
    else
    {
        printf("open %s error\r\n",filename);
        return 1;
    }

    fseek(fin1, 0, SEEK_END);
    size1 = ftell(fin1);
	fseek(fin1, 0, SEEK_SET); 


    printf("file size = %d\r\n", size1);

    char* buf = malloc(size1);  //开一个空间
    if(buf == NULL)
    {
    	printf("error: size1 malloc %d\n",size1);
    	fclose(fin1);
    	return 1;
    }


    readcount = 0;
	do
    {
        bw = fread(buf+readcount, 1, size1-readcount, fin1);
        if(bw == 0)
        	break;
        readcount += bw;
    } while (readcount < size1);

    ret = cal_md5(md5_readBuf, buf, size1);
    //md5(buf, size1, md5_readBuf);
    if(!ret) 
    	printf("cal_md5 = %s\n",md5_readBuf);


    free(buf);
    fclose(fin1);
// 	strcat(cmd,filename);

// 	filep = popen(cmd,"r");
// 	if(!filep)
// 		return -1;
//     ret = fread(md5_readBuf,32,1,filep);
 
// //    printf("get_file_md5sum = %s\n",md5_readBuf);

//     pclose(filep);

    return ret;
}





void combin_file(char* file1,char* file2,char* outfilename)
{
	FILE *fin1,*fin2;// *fout;
    int size1 = 0,size2 = 0,total_size = 0;
    char outnamebuf[64] = {0};
    uint16_t posision = 0;   //位置
    int bw = 0;       
    int readcount = 0;
    int ret,i;
    int lcd_inch = 0;

    if(file1== NULL || file2 == NULL)
    {
    	printf("ERROR : file is NULL \n");
    	return ;
    }

    //1. 这一段是考虑没有指定输出文件名的情况,但是实际效果没有测试,可能有问题。
    //形成输出文件名
    if(outfilename == NULL)
    {
    	size1 = strlen(file1)-4;
    	if(size1 > 29)
    		size1 = 29;

    	size2 = strlen(file2)-4;
    	if(size2 > 29)
    		size2 = 29;
    	strncpy(outnamebuf,file1,size1); //不需要后缀
    	strcat(outnamebuf,"_");  //加入下划线
    	strncat(outnamebuf,file2,size2);
    	strcat(outnamebuf,".bin");
    }
    else
    {
    	size1 = strlen(outfilename);
    	if(size1 > 63)  //文件名太长了
    	{
    		size2 = size1;
    		size1 = 59;
    	}	
    	strncpy(outnamebuf,outfilename,size1);

    	if(size2 > 63)
    	{
    		strcat(outnamebuf,".bin");
    	}
    }	
    printf("outnamebuf = %s\n",outnamebuf);



    //2.得到app文件的md5值,存在全局变量中
    get_file_md5sum(file2);

    //3.打开iap的bin文件,全部读取处理
    fin1 = fopen(file1, "rb");
    if (fin1 != NULL)
    {
        /* 文件打开成功*/
        printf("open %s success\r\n",file1);
    }
    else
    {
        printf("open %s error\r\n",file1);
        return ;
    }

    //4.打开app的bin文件,全部读取处理
    fin2 = fopen(file2, "rb");
    if (fin2 != NULL)
    {
        /* 文件打开成功*/
        printf("open %s success\r\n",file2);
    }
    else
    {
    	fclose(fin1);
        printf("open %s error\r\n",file2);
        return ;
    }

    //5.得到app文件的大小
    fseek(fin2, 0, SEEK_END);
    size2 = ftell(fin2);
    
    //6.得到iap文件的大小
	fseek(fin1, 0, SEEK_END);
    size1 = ftell(fin1);
	fseek(fin1, 0, SEEK_SET); 


    printf("file2 size = %d\r\n", size2);
    total_size = size2+0x6000;  //7.需要分配的空间的大小
    char* buf = malloc(total_size);  //开一个空间
    if(buf == NULL)
    {
    	printf("error: total_size malloc %d\n",total_size);
    	fclose(fin1);
    	fclose(fin2);
    	return ;
    }

    //8.因为flash中没有数据的位置都是0xff,所以把缓存填充0xff
    memset(buf,0xff,total_size);   //先填充0xff

	
	//9.读取appbin文件的内容,先判断前8个字节的内容,是否符合bin文件的特征。
	fseek(fin2, 0, SEEK_SET);
	ret = fread(buf, 1, 8, fin2);   //从app文件中读取4个字节
	if(ret == 8)
	{
		if (((*(uint32_t*)buf) & 0xfFFE0000 ) != 0x20000000)
		{
			printf("image addr 0 != 0x20000000\n");
			printf("ERROR: bad image(app.bin)!!!!! combin cancle!!!,please check bin file!!!");
			fclose(fin1);
    		fclose(fin2);
			free(buf);
			return ;
		}
		else if(((*(uint32_t*)(buf+4)) & 0xfFFf0000 ) != 0x08000000)
		{
			printf("image  addr %#x != ApplicationAddress %#x\n",((*(uint32_t*)(buf+4)) & 0xfFFffc00 ),0x08000000);
			printf("ERROR: bad image(app.bin)!!!!! combin cancle!!!,please check again!!!");
			fclose(fin1);
    		fclose(fin2);
			free(buf);
			return ;
		}

		posision = ((*(uint16_t*)(buf+4)) & 0xfc00 );   //10.关键的一部,bin文件中可以知道app的偏移值,这里考虑的是不同单片机的偏移不同的问题
		printf("posision = %#x\n",posision);
	}
	else
	{
		printf("error: fread(buf, 1, 2, fin2)\n");
        fclose(fin1);
        fclose(fin2);
        free(buf);
		return;
	}

	//11.正常偏移是24k左右,但是综合考虑,选择了2k,怕有的程序的偏移过小。
    if(posision < 2048)
    {
        printf("ERROR: bad app image(bin)!!!!! ,please check app.bin!!!\n");
        fclose(fin1);
        fclose(fin2);
        free(buf);
        return;
    }

	//12. iap的大小超过了整个偏移区的地址
    if(size1 > posision-1024)
	{
		printf("ERROR: bad iap image(bin)!!!!! ,please check iap.bin!!!\n");
		fclose(fin1);
		fclose(fin2);
		free(buf);
	}

	//13.偏移不是24k的情况,调整一下大小
	if(posision <= 0x6000) //
	{
		total_size = total_size - 0x6000 + posision;   //重新调整一下大小
		printf("total_size = %d\n",total_size);
	}
	else
	{
		printf("ERROR: bad app image(bin)!!!!! ,please check app.bin!!!\n");
		fclose(fin1);
        fclose(fin2);
        free(buf);
        return;
	}


	//14.文件2指针还原,指向文件开始的位置
	fseek(fin2, 0, SEEK_SET);

	//15.把iap的bin文件全部读出来
	printf("size1 = %d\n",size1);
	readcount = 0;
	do
    {
        bw = fread(buf+readcount, 1, size1-readcount, fin1);
        if(bw == 0)
        	break;
        readcount += bw;
    } while (readcount < size1);


    //16.判断bin的合法性,
    if (((*(uint32_t*)buf) & 0xfFFE0000 ) != 0x20000000)
	{
		printf("image addr 0 != 0x20000000\n");
		printf("ERROR: bad image(iap.bin)!!!!! combin cancle!!!,please check bin file!!!\n");
		fclose(fin1);
		fclose(fin2);
		free(buf);
		return ;
	}
	else if(((*(uint32_t*)(buf+4)) & 0xfFFffc00 ) != 0x08000000)
	{
		printf("image  addr %#x != ApplicationAddress %#x\n",((*(uint32_t*)(buf+4)) & 0xfFFffc00 ),0x08000000);
		printf("ERROR: bad image(iap.bin)!!!!! combin cancle!!!,please check again!!!\n");
		fclose(fin1);
		fclose(fin2);
		free(buf);
		return ;
	}



    //17.把app的bin文件全部读出来
    printf("size2 = %d\n",size2);
	readcount = posision;  //app的位置,在bin中已经指定
	do
    {
        bw = fread(&buf[readcount], 1, size2, fin2);
        if(bw == 0)
        	break;
        readcount += bw;
    } while (readcount-posision < size2);


    //18,缓存的特定位置加入下载标记,升级标记,文件大小和md5值
    posision -= 0x400;   //退1k字节
    printf("posion2 = %#x\n",posision);
    (*(uint32_t*)(buf+4+posision)) = size2;  //只保存app 的bin文件大小
    (*(uint16_t*)(buf+posision)) = 0xff;     //不需要升级

    //19.这个地方比较特殊,设置对不同屏幕设置不同标记,方便单片机区分屏幕
    if(strstr(file2,"old5") != NULL)
    {
    //    lcd_inch = 4;  
        (*(uint8_t*)(buf+posision-1)) = 5;
        printf("detect old5inch\n"); 
    }
    else if(strstr(file2,"7inch") != NULL)
    {
    //     lcd_inch = 5;  
         (*(uint8_t*)(buf+posision-1)) = 4; 
         printf("detect 7inch\n"); 
    }
    else if(strstr(file2,"new5") != NULL)
    {
    //    lcd_inch = 6;
        (*(uint8_t*)(buf+posision-1)) = 6; 
        printf("detect new5inch\n"); 
    }

    //20,缓存的特定位置md5值,后面以为要区分多个单片机的bin,所以不同的单片机进行了一些小的偏移
    //所以md5的位置也不会是固定的。同一个单片机肯定是固定在某个位置。
    posision += 512;   //写入md5的值。2023-06-12 hj的+8
    if(strstr(file2,"hj22134") != NULL)
        posision += 8; // hj的+8
    printf("posion3 = %#x\n",posision);
    for(i=0;i<32;i++)
    {
    	buf[i+posision] = md5_readBuf[i];
    }

    fclose(fin1);
    fclose(fin2);

    //21.将缓存的内容生成第三个文件
    fin1 = fopen(outnamebuf, "wb");
    if (fin1 != NULL)
    {
        /* 文件打开成功*/
        printf("3.open %s success \n",outnamebuf);
    }
    else
    {
        printf("3.open %s error \n",outnamebuf);
        free(buf);
        return ;
    }

    //22.写入文件
    readcount = 0;
	do
    {
        bw = fwrite(&buf[readcount], 1, total_size, fin1);
        readcount += bw;
    } while (readcount < total_size);

    fclose(fin1);
    free(buf);

    printf("combin complete!! size = %d\n",total_size);

    return;
}




int main(int argc,char* argv[])
{
	char* outfilename = NULL;

	if(argc < 3){
		printf("Usage : %s <file1.bin> <file2.bin> [outfilename]\n",argv[0]);
		return -1;
	}

	if(argc >= 4)
	{
		outfilename = argv[3];
	}

	//第一个文件,与第二个文件合并,生成第三个文件,第三个可以不指定。
	combin_file(argv[1],argv[2],outfilename);

	return 0;

}



到了这里,关于gd32f103vbt6 串口OTA升级5-combin部分的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • GD32F103输入捕获

    GD32F103输入捕获程序,经过多次测试,终于完成了。本程序将TIMER2_CH2通道映射到PB0引脚,捕获PB0引脚低电平脉冲时间宽度。PB0是一个按钮,第1次按下采集一个值保存到TIMER2_CountValue1中,第2次按下采集一个值保存到TIMER2_CountValue2中,然后计算其低电平时间宽度。 网上也有人写

    2024年02月14日
    浏览(45)
  • GD32F103 硬件SPI通信

    SPI既可以做主机也可以做从机。 当做主机时。MOSI,SCK,CS都是作为输出。 而作为从机时。MOSI,SCK,CS都是作为输入。  所以SPI的硬件电路应该实现这样的功能。 1. GD32框图 如下图做主机的数据流向:   如下图做从机的数据流向:    2. STM32框图  通过一些寄存器的配置来控制

    2024年02月02日
    浏览(44)
  • GD32F103x 定时器

    STM32的定时器主要分为三种: 高级定时器、通用定时器、基本定时器 。 即:高级定时器具有捕获/比较通道和互补输出,死区时间,通用定时器只有捕获/比较通道,基本定时器没有以上两者。  1. 基本定时器 1.时钟源 时钟源来自RCC的CK_TIMER,就是内部时钟(CK_INT)直接经过控

    2024年02月07日
    浏览(44)
  • GD32F103VE侵入事件

    GD32F103VE的TAMPER引脚(PC13),当PC13输入低电平时,会产生一个侵入检测事件。它会将所有“ 数据备份寄存器 ”内容清除。 这个功能有什么用? 一是防止被人开壳,抄袭。二是自毁功能。 直奔主题,多一句就是浪费时间。测试程序如下:  main.c程序 如下:  

    2024年02月14日
    浏览(40)
  • GD32F103VET输出PWM波形

    GD32F103VET将TIMER0_CH3映射到PE14引脚,使其输出PWM波形。测试时,使用示波器看PE14引脚输出的波形,效果更直观。 TIMER0之PWM输出引脚映射如下: TIMER0_REMAP[1:0]=\\\"00\\\"(没有映射): TIMER0_CH0默认被映射到PA8引脚 TIMER0_CH1默认被映射到PA9引脚 TIMER0_CH2默认被映射到PA10引脚 TIMER0_CH3默认被映射

    2024年02月14日
    浏览(41)
  • 基于gd32f103移植freemodbus master 主栈

    1.移植freemodbus master需要先移植RT-Thread操作系统 GD32F103C8T6移植 RTT Nano 教程-CSDN博客 2.移植freemodbus master协议栈 在移植了RTT以后,我们需要移植就只有串口相关的函数 移植freemodbus master协议栈具体步骤 下载移植freemodbus master协议栈 源码 添加协议栈文件 向mdk添加头文件路径 修改

    2024年01月18日
    浏览(48)
  • GD32F103硬件I2C0通讯

    GD32F103的I2C模块有I2C0和I2C1;本程序使用I2C0功能模块; I2C0引脚复用和重映射: 当I2C0_REMAP=0时,I2C0引脚复用功能,I2C0_SCL映射到PB6引脚,I2C0_SDA映射到PB7引脚; 当I2C0_REMAP=1时,I2C0引脚重映射,I2C0_SCL映射到PB8引脚,I2C0_SDA映射到PB9引脚; I2C1引脚只有复用引脚: I2C1_SCL映射到PB10引脚,I2C1_SDA映射到

    2024年02月13日
    浏览(56)
  • stm32f103与openmv串口通信

    串口通信是指通过串行通信接口进行数据传输的一种通信方式。在串口通信中,数据被分成一个个的字节,按照一定的顺序依次发送和接收。串口通信通常使用UART(通用异步收发传输)协议进行数据传输。 串口通信在嵌入式系统中应用非常广泛,其主要用途包括: 调试和监

    2024年02月13日
    浏览(50)
  • STM32F103实现USB虚拟串口

            今天分享一下STM32F103如何实现虚拟串口,目标是让新手也能上手,如果谁没看懂或者照着做功能没有实现可以私信我,只要我看到一定回复。        本次使用的是STM32F103C8T6核心板,按以下步骤新建一个STM32CubeMX工程。        步骤一 :先输入MCU型号搜索芯片,软件

    2024年02月09日
    浏览(47)
  • STM32F103C8T6串口通信

      首先来看一下需要操作的函数,以及配置的步骤: 图1                                                  图2   Code: usart.c #include \\\"usart.h\\\" void ustart_Init(void ) { GPIO_InitTypeDef GPIO_Init_Ustar ; // 定义输出端口TX的结构体对象 USART_InitTypeDef USTART_Init; // 定义串口初始化结构体对象

    2024年02月16日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包