最近在编写MCU程序,BootLoader要支持UART和CAN升级,做一些记录.下面是Hex升级文件的解析方法,上位机调试用,能够将Hex的各个Block进行分组,每个块的起始地址和大小,总字节数等信息提取.
void ReadHexFileToStruct(char *FileName, HEX_FEIL_T *HexFile)
{
FILE *fp;
ssize_t size;
int status = 0;
char RowData[48]; //逐行读取,每行数据缓存
uint32_t i = 0;
uint32_t RowDataByte = 0; //单行数据块字节数
uint32_t OffsetAddress = 0; //扩展线性地址
uint32_t ReAddr = 0; //上一数据行起始地址
uint32_t Len = 0; //HEX每行有效数据字节数
uint32_t ReLen = 0; //HEX前一次数据长度
uint32_t Addr=0; //HEX每行起始地址
uint8_t Type = 0; //HEX单行数据的类型
ReadHexFileInit(HexFile); //初始化缓存区
status = GetFileInfo (FileName, &size); //获取文件信息
if(status > 0) //0:不存在,1:文件存在,-1:已打开
{
if((fp = fopen(FileName, "r")) == NULL) //打开文件
{
Msg("Hex文件不存在!");
return ; //空指针
}
while(fgets (RowData, 48, fp) != NULL) //读行函数fgets
{
if(RowData[0] == ':') //首字判断:偏移1,“:”0x3A
{
Len = CharToHexUchar(RowData + 1); //数据长度:偏移2- 1,2
Addr = CharToHexInt(RowData + 3) ; //起始地址:偏移4- 3,4,5,6
Addr|= (OffsetAddress << 16);
Type = CharToHexUchar(RowData + 7); //类型:偏移2 -7,8
switch(Type)
{
case 0x00: //数据
if(Addr > (ReLen + ReAddr)) //判断为新数据块
{
if(RowDataByte == 0) //是否为首行数据字节数
{
HexFile->BlockStartAddr[HexFile->HexBlockTotalNumber] = Addr;//记录新数据块的起始地址
}
else //不是首行
{
HexFile->BlockDataLength[HexFile->HexBlockTotalNumber]= RowDataByte;//数据长度
RowDataByte = 0; //重新开始计数
HexFile->BlockStartAddr[++HexFile->HexBlockTotalNumber] = Addr; //记录新数据块的起始地址
}
}
for(i = 0;i < Len; i++)
{
HexFile->HexBlockData[HexFile->HexBlockTotalNumber][RowDataByte++] = CharToHexUchar(RowData + 9 + i*2); //数据: 9,10起始
}
ReAddr = Addr; //保存当前地址,下一次使用
ReLen = Len; //保存当前长度,下一次使用
break;
case 0x04: //扩展线性地址记录
OffsetAddress = CharToHexInt(RowData + 9); //偏移地址
break;
case 0x01: //地址,结束
HexFile->BlockDataLength[HexFile->HexBlockTotalNumber]= RowDataByte; //数据长度
HexFile->HexBlockTotalNumber++;
break;
}
}
}
fclose(fp);
StringUpperCase(FileName);
Msg(FileName);
Msg("\r\nHex文件读取成功, 大小%d字节, 数据分块:%d \r\n",size,HexFile->HexBlockTotalNumber);
for(i = 0; i < HexFile->HexBlockTotalNumber; i++)
{
HexFile->HexTotalByteNumber += HexFile->BlockDataLength[i];
Msg("数据块:%d, 起始地址:0x%.4X, 结束地址:0x%.4X, 数据长度:%6d字节\r\n", i+1, HexFile->BlockStartAddr[i], HexFile->BlockStartAddr[i] + HexFile->BlockDataLength[i] - 1, HexFile->BlockDataLength[i]);
}
}
else
{
Msg("Hex文件不存在,%s\r\n",FileName);
}
}