固件解析-HEX文件

1:什么是hex文件 

       以*.hex为后缀的文件我们称之为HEX文件。hex是intel规定的标准,hex的全称是Intel HEX,此类文件通常用于传输将被存于ROM或EEPROM中的程序和数据。是由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。 HEX的英语原始意思是16进制。这种文件格式主要用于保存单片机固件。 整个文件以行为单位,每行以冒号开头,内容全部为16进制码,2个ASCII码字符表示1个Hex字节

2:hex文件 格式分析

     找份单片机工程编译下,基本都支持HEX文件格式输出,本文分析一份STM32固件数据。

       选择输出类型为:Intel Extended hex  编译源代码输出*.hex文件。通过Notepad++打开,看到它通过颜色帮我们分辨出各个数据类型。

2.1:数据类型

类型描述备注
行开始换行回车行结束
02数据长度2个字符
0000地址4个字符
04功能重点关注
08 00数据数据字符=数据长度*2
F2校验和前面四项相加补码 0x02+0x00+0x00+0x04+0x08+0x00 = 0x0e  取反+1 = 0xF2

2.2:功能码

功能码描述备注
00数据行
01文件结束行再文件最后一行出现
02扩展段地址单片机上不出现
03开始段地址单片机上不出现
04扩展线性地址单片机高地址两字节  0x0800xxxx stm32 flash地址

 

3:代码解析Hex文件

     通过C++解析Hex文件得到若干个数据块,开发过程中没有设置段基本就是一块数据。我们定义数据结构如下:

class RecordBlock
{
     public:
     int address;         //地址
     QByteArray data;//数据
};

通过调用下面函数得到HEX数据块集合

int HexFirmware::ParseFile(QString path, QList<RecordBlock> &BlockList)
     {
         //step1:清空块列表
         BlockList.clear();
         //step2:清空记录行列表
         recordLines.clear();

         QByteArray HLine;
         //step3:声明一个流读取类
         QFile aFile(path);
          if (!aFile.exists()) //文件不存在
              return -1;
          if (!aFile.open(QIODevice::ReadOnly | QIODevice::Text)) //打开失败
              return -2;

         QByteArray data;
         int dataLenght;
         bool ok;
         ExtendedAddr = 0;
        while (!aFile.atEnd())
         {
            //| MARK | RECLEN | OFFSET | RECTYP | DATA | CHKSUM |
             HLine = aFile.readLine();
             if(HLine.size()<11) return -5;//数据长度错误
             if (HLine[0] != ':')//":"开头的不用打印
             {
                  return -3;//不以“:”开头不解析  头格式错误
             }
             else
             {
                 int type = HLine.mid(7, 2).toInt(&ok,16);//功能类型
                 if(ok==false) return -4; //类型错误
                 unsigned  int address;
                 int lineLen;
                 int offse;
                 int checkNum;
                 switch (type)
                 {
                    case 0: //数据部分
                       HeadLineStr =  QString(HLine);
                       HLine.remove(0,1); //移除":"
                       address = HLine.mid(2, 4).toInt(&ok,16);//文件类型
                       if(ok==false) return -5; //地址错误
                       if (ExtendedAddr != 0x0000)
                       {
                          address |= (ExtendedAddr<<16);
                       }
                       dataLenght  = HLine.mid(0,2).toInt(&ok,16);
                       if(ok==false) return -5; //地址错误
                       lineLen =  (dataLenght+5)*2; //
                       if((dataLenght+5)*2 > HLine.size()) //数据长度错误
                          return -6; //地址错误
                       checkNum =  HLine.mid(lineLen-2,2).toInt(&ok,16);
                       if(ok==false) return -8; //校验错误
                       offse = 8;
                       if (checkSum(data,HLine,lineLen-2,offse, checkNum))
                       {
                           RecordLine S19Data;
                           S19Data.address = address;
                           //纯数据,10 =  总个数2 + 地址4 + 类型2 + 校验2
                           S19Data.data = data;
                           //纯数据长度,去掉地址2位,校验1位 = 3
                           S19Data.count = data.size();
                           recordLines.append(S19Data);
                          // qDebug()<<  S19Data.data.toHex();//
                       }
                     break;
                   case 0x04:

                     HeadLineStr =  QString(HLine);
                     HLine.remove(0,1); //移除":"
                     address = HLine.mid(2, 4).toInt(&ok,16);//文件类型
                     if(ok==false) return -5; //地址错误
                     dataLenght  = HLine.mid(0,2).toInt(&ok,16);
                     if(ok==false) return -5; //地址错误
                     lineLen =  (dataLenght+5)*2; //
                     if((dataLenght+5)*2 > HLine.size()) //数据长度错误
                        return -6; //地址错误
                     ExtendedAddr = HLine.mid(8, 4).toInt(&ok,16);
                     if(ok==false) return -9; //地址错误
                     break;
                 }

             }

         }
         aFile.close();
        //地址升序排序
         devListSort(recordLines);
         //把文件中每一行的数据组合成若干个地址开头的整块数据,放在s19Block里用于发送
         int nextAddress = 0xFFFF;
         RecordBlock S19Block;
         for (int i = 0; i < recordLines.size(); i++)
         {
             if (i == 0)//第一个循环
             {
                // HexBlock = new HexRecordBlock();
                 //获取下一条记录的起始地址,并将本条记录存储再数据块中
                 nextAddress = getNextAddress(S19Block, recordLines, i);
                 if (i == recordLines.size() - 1)
                 {
                     //已经循环到底,只有一个block
                     BlockList.push_back(S19Block);
                 }
             }
             else//如果不是第一条记录
             {
                 if (nextAddress == recordLines[i].address)
                 {
                     joinHexBlockData(S19Block.data, recordLines[i].data);
                     nextAddress = recordLines[i].address + recordLines[i].count;
                     if (i == recordLines.size() - 1)
                     {
                         //已经循环到底,只有一个block
                         BlockList.append(S19Block);
                     }
                 }
                 else if (nextAddress < recordLines[i].address)
                 {
                     BlockList.append(S19Block);
                     S19Block.data.clear();
                     nextAddress = getNextAddress(S19Block, recordLines, i);
                     if (i == recordLines.size() - 1)
                     {
                         //已经循环到底,只有一个block
                         BlockList.append(S19Block);
                     }
                 }
                 else
                 {
                    qDebug()<<"地址覆盖";
                     return -8;
                 }
             }
         }
         return 0;
     }

//排序
void HexFirmware::devListSort(QList<RecordLine > &list)
{
  qSort(list.begin(), list.end(), compare);
}

//检验核对
bool HexFirmware::checkSum(QByteArray &hex,QByteArray data, int len, int offset,unsigned        char checkNum)
    {
        //校验
        unsigned int sum = 0;
        bool ok;
        hex.clear();
        for (int i = 0; i <len; i = i + 2)
        {
            unsigned char value = data.mid(i,2).toInt(&ok,16);
            if(ok==false) return false;
            if(i>=offset)
            hex.append(value);
            sum += value;
        }
        //取低字节,1位
       unsigned  char lowSum = sum&0xff;
       unsigned  char temp = 0x100 - lowSum;
        if (temp == checkNum)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

获得数据后就可以通过CAN传输来给设备升级!!!

1:代码通过一行一行的解析数据,并对数据检验核实。

2:通过地址排序行数据。理论是不需要的,生成是按照地址顺序生成。

3:把连续地址合并成大块。好处在于升级可以按自定义数据长度传输如ISO-15765 最大一帧可以传输4k数据

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值