hex文件解析实现代码

Hex文件格式介绍(介绍部分转载地址:http://www.forwhat.cn/post-240.html

Hex文件是可以烧录到MCU中,被MCU执行的一种文件格式。如果用记事本打开可发现,整个文件以行为单位,每行以冒号开头,内容全部为16进制码(以ASCII码形式显示)。Hex文件可以按照如下的方式进行拆分来分析其中的内容:

例如 “:1000080080318B1E0828092820280B1D0C280D2854”可以被看作“0x10 0x00 0x08 0x00 0x80 0x31 0x8B 0x1E 0x08 0x28 0x09 0x28 0x20 0x28 0x0B 0x1D 0x0C 0x28 0x0D 0x28 0x54”

第一个字节 0x10表示本行数据的长度;

第二、三字节 0x00 0x08表示本行数据的起始地址;

第四字节 0x00表示数据类型,数据类型有:0x00、0x01、0x02、0x03、0x04、0x05。

'00' Data Rrecord:用来记录数据,HEX文件的大部分记录都是数据记录

'01' End of File Record: 用来标识文件结束,放在文件的最后,标识HEX文件的结尾

'02' Extended Segment Address Record: 用来标识扩展段地址的记录

'03' Start Segment Address Record:开始段地址记录

'04' Extended Linear Address Record: 用来标识扩展线性地址的记录

'05' Start Linear Address Record:开始线性地址记录

然后是数据,最后一个字节 0x54为校验和。

校验和的算法为:计算0x54前所有16进制码的累加和(不计进位),检验和 = 0x100 - 累加和

在上面的后2种记录,都是用来提供地址信息的。每次碰到这2个记录的时候,都可以根据记录计算出一个“基”地址。对于后面的数据记录,计算地址的时候,都是以这些“基”地址为基础的。

HEX文件都是由记录(RECORD)组成的。在HEX文件里面,每一行代表一个记录。记录的基本格式为:

Record mark ‘:’

Length

Load offset

Record type

INFO or DATA

CHKSUM

1 byte

1 byte

2 bytes

1 byte

n bytes

1 byte

看个例子:

:020000040008F2

:10000400FF00A0E314209FE5001092E5011092E5A3

:00000001FF      

对上面的HEX文件进行分析:

第1条记录的长度为02,LOAD OFFSET为0000,RECTYPE为04,说明该记录为扩展段地址记录。数据为0008,校验和为F2。从这个记录的长度和数据,我们可以计算出一个基地址,这个地址为(0x0008 << 16)。后面的数据记录都以这个地址为基地址。

第2条记录的长度为10(16),LOAD OFFSET为0004,RECTYPE为00,说明该记录为数据记录。数据为FF00A0E314209FE5001092E5011092E5,共16个BYTE。这个记录的校验和为A3。此时的基地址为0X80000,加上OFFSET,这个记录里的16BYTE的数据的起始地址就是0x80000 + 0x0004 = 0x80004.

第3条记录的长度为00,LOAD OFFSET为0000,TYPE = 01,校验和为FF。说明这个是一个END OF FILE RECORD,标识文件的结尾。

在上面这个例子里,实际的数据只有16个BYTE:FF00A0E314209FE5001092E5011092E5,其起始地址为0x0004.

以下是我的代码实现:

头文件:

#ifndef CHEX_H
#define CHEX_H

#include <QFile>

const quint8 MIN_HEX_LINE_COUNT_LENGHT = 12;

typedef enum __tagHexErrorCode
{
    HEX_NO_ERROR = 0,
    HEX_FORMAT_ERROR,
    HEX_VERIFY_ERROR,
    HEX_LENGHT_ERROR,
    HEX_USERPAPR_EEROR,
}EHexErrorCode;

typedef enum __tagHexType
{
    RECORD_DATA = 0,
    RECORD_END_OF_FILE,
    RECORD_EXTENDED_SEGMENT_ADDRESS,
    RECORD_START_SEGMENT_ADDRESS,
    RECORD_EXTENDED_LINEAR_ADDRESS,
    RECORD_START_LINEAR_ADDRESS,
    RECORD_HEX_MAX,
}emHexType;

typedef struct __tagHexLineData
{
    emHexType   type;
    quint8      count;
    quint32     address;
    quint8      data[80];
    quint8      checksum;
    quint8      datalen;
}stHexLineData;

class CHex
{
public:
    CHex();
    EHexErrorCode getHexLineData(QByteArray bydata,stHexLineData *p);
private:
    char ConvertHexChar(char ch);
};

#endif // CHEX_H

源文件:

#include "chex.h"

const QString HexTypeTable[6] =
{
    "00","01","02","03","04","05",
};

CHex::CHex()
{

}

char CHex::ConvertHexChar(char ch)
{
    if((ch >= '0') && (ch <= '9'))
        return (ch-0x30);
    else if((ch >= 'A') && (ch <= 'F'))
        return ((ch-'A')+10);
    else if((ch >= 'a') && (ch <= 'f'))
        return ((ch-'a')+10);
    else return (-1);
}

EHexErrorCode CHex::getHexLineData(QByteArray bydata,stHexLineData *p)
{
    quint8 i = 0;
    quint8 cs_temp = 0;
    QString str(bydata);
    char *pcdata = bydata.data();
    quint32 linelen = str.size();
    if((linelen < MIN_HEX_LINE_COUNT_LENGHT)) {return HEX_LENGHT_ERROR;}
    if(*pcdata != 0x3A) {return HEX_FORMAT_ERROR;}//必须以":"号开始
    //获取Type
    QString stype = str.mid(7,2);
    for(i = 0; i < RECORD_HEX_MAX; i++)
    {
        if(stype == HexTypeTable[i])
        {
            p->type = (emHexType)i;
            break;
        }
    }
    if(i == RECORD_HEX_MAX) {qDebug("HEX_FORMAT_ERROR");return HEX_FORMAT_ERROR;}
    cs_temp += (ConvertHexChar(*(pcdata + 7)) << 4) | ConvertHexChar(*(pcdata + 8));
    //获取count
    p->count = (ConvertHexChar(*(pcdata + 1)) << 4) | ConvertHexChar(*(pcdata + 2));
    cs_temp += p->count;
    if(p->count != (((linelen - 2) / 2) - 5)) {qDebug("HEX_FORMAT_ERROR");return HEX_FORMAT_ERROR;}
    //获取address
    p->address = (ConvertHexChar(*(pcdata + 3)) << 12) | (ConvertHexChar(*(pcdata + 4)) << 8) | (ConvertHexChar(*(pcdata + 5)) << 4) | ConvertHexChar(*(pcdata + 6));
    cs_temp += (p->address >> 8) & 0xFF;
    cs_temp += p->address & 0xFF;
    //获取data
    for(i = 0; i < p->count; i++)
    {
        p->data[i] = (ConvertHexChar(*(pcdata + 2*i + 9)) << 4) | ConvertHexChar(*(pcdata + 2*i + 10));
        cs_temp += p->data[i];
    }
    p->checksum = (ConvertHexChar(*(pcdata + 2*i + 9)) << 4) | ConvertHexChar(*(pcdata + 2*i + 10));
    if(p->checksum != ((0x100 - cs_temp) & 0xFF))
    {
        qDebug("HEX_VERIFY_ERROR");
        return HEX_VERIFY_ERROR;
    }
    p->datalen = p->count;

    return HEX_NO_ERROR;
}


### 解析 Hex 文件的方法与工具 #### 工具介绍 Hex 文件解析可以通过多种方式进行,具体取决于需求场景以及使用的开发环境。以下是几种常见的工具及其功能: 1. **Hexview** Hexview 是一款强大的工具,专门设计用于处理不同格式的二进制文件,包括 hex、srec 和 bin 等[^2]。它不仅提供图形化界面(GUI),还支持命令行操作,方便开发者集成到自动化脚本中。通过 Hexview,用户可以轻松实现以下目标: - 查看和编辑 hex 文件的内容。 - 将 hex 文件转换为其他格式(如 bin 或 s19)。 - 提取特定地址范围的数据。 2. **CAPL 编程语言** CAPL(Communication Access Programming Language)是一种嵌入式系统的编程语言,常用于 CANoe 软件环境中。如果需要在 CAN 总线通信上下文中解析 hex 文件,则可以利用 CAPL 实现自定义逻辑[^1]。例如,读取 Intel HEX 文件并将其内容加载到内存映射区域中以便进一步分析或执行。 #### 手动解析流程 对于不依赖第三方软件的情况,手动编写代码解析 hex 文件也是一种可行方案。以下是基于 Python 的简单示例,展示如何解析标准 Intel HEX 格式的文件: ```python def parse_hex_file(file_path): with open(file_path, 'r') as file: lines = file.readlines() result = [] for line in lines: if not line.startswith(':'): continue # 非法行跳过 byte_count = int(line[1:3], 16) # 字节数 address = int(line[3:7], 16) # 地址 record_type = int(line[7:9], 16) # 记录类型 (00=数据, 01=EOF) if record_type != 0: # 只关心数据记录 break data = [int(line[i:i+2], 16) for i in range(9, 9 + 2 * byte_count, 2)] # 数据部分提取 checksum = sum([byte_count] + [(address >> 8), (address & 0xFF), [record_type]] + data) % 256 # 校验计算 expected_checksum = int(line[-3:-1], 16) # 获取期望校验值 if checksum != expected_checksum: # 校验失败提示错误 raise ValueError(f"Checksum error at {line}") result.extend(data) return result ``` 此函数实现了基本的 Intel HEX 文件解析逻辑,并验证每条记录的有效性[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值