基于CAPL的HEX文件解析

  • 🍅 我是蚂蚁小兵,专注于车载诊断领域,尤其擅长于对CANoe工具的使用
  • 🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】
  • 🍅 玩转CANoe,博客目录大全,点击跳转👉

📘前言

  • 🍅 车载测试必不可少的是刷写,行业内有很多格式的刷写文件,S19,HEX,BIN,还有一些主机厂自定义的比如Volvo/GeeaVBFCheryCBF

  • 🍅 本章节先了解HEX文件

请添加图片描述

目录

  • 📘前言
  • 📙 HEX 文件的格式简介
    • 🍅 实例说明
    • 🍅 HEX View 神器
  • 📙CAPL解析HEX文件源码
  • 🌎总结


📙 HEX 文件的格式简介

  • Hex 全称 (Intel HEX)文件是由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。在Intel HEX文件中,每一行包含一个HEX记录。这些记录由对应机器语言码和/或常量数据的十六进制编码数字组成。Intel HEX文件通常用于传输将被存于ROM或者EPROM中的程序和数据。大多数EPROM编程器或模拟器使用Intel HEX文件

Intel Hex的格式这个record包含6部分内容,其格式是这样的:

在这里插入图片描述

:020000040100F9
:20000000709EE4057090C0007078052054640010707B0128546400105064000061F35464B8
:2000200000007060E0007060C0037C73FBA670FEE7FB50E7800070E0C80BE62F7168E00AEB
:200040007170C1007200E0007220E0007240E0007260E0007280E00072A0E00072C0E00020
格式说明
Start code数据每行都由冒号开头
Byte count数据长度 1 Byte ,表示本行数据的长度,大值是255 (0xFF). 16 (0x10) 和32 (0x20)是最常用的。
Address数据地址 2 Byte ,表示Memory数据开始16-bit地址偏移。物理地址通常是有这个偏移加上基地址
Record type数据类型 1 Byte, 00 ~ 05, 表示不同数据段的含义
Data具体数据 N Byte ,表示本行中数据字节的数量,它和A说明的数据长度一致
Checksum比如:0300300002337A1E的计算方法:
数据和为:03 + 00 + 30 + 00 + 02 + 33 + 7A = E2,这个E2的补码是1E,即这个数据record的补码

数据类型详解
‘00’数据记录:用来记录数据,HEX文件的大部分记录都是数据记录
‘01’文件结束记录:用来标识文件结束,放在文件的最后,标识HEX文件的结尾
‘02’扩展段地址记录:用来标识扩展段地址的记录
‘03’开始段地址记录:开始段地址记录
‘04’扩展线性地址记录:用来标识扩展线性地址的记录
‘05’开始线性地址记录:开始线性地址记录

一旦出现段地址或者线性地址,之后所有数据都要加偏移地址,直到出现一个新的段地址或者线性地址,再重新变更偏移地址。数据物理地址为:线性地址左移16位+段地址左移4位+偏移地址。

在这里插入图片描述

  • 基地址:0108左移16位à0x01080000;
  • 扩展段地址:12FF左移4位à0x00012FF0;
  • 数据偏移地址:0x0100;
  • 实际物理地址=基地址+扩展段地址+偏移地址=0x010930F0。

🍅 实例说明

  • Notepad++ 打开选,自动识别,根据颜色可以看出HEX的记录格式
  • 看到的是16进制显示的ASCII文本格式

在这里插入图片描述

重点讲解下 Record type这个参数:

  • 因为HEX的地址段只有两个字节表示,只能寻址到16位,显然是不够的,所以就有了拓展地址(Record type =4),比如 头行数据:020000040100F9 ,02表示数据段的长度,2个字节;0000是默认填充的,04是Record type,表示后面的两个字节0x0100是拓展地址,也就是32位寻址的高16位,那么下面从第二行开始的地址段都会加上这个高地址段组成真正的刷写地址,比如刷写地址是0x01000000
  • HEX文件大多数行的 Record type 都是00 ,表示是数据段
  • HEX文件最后一行的 Record type 都是01 ,表示是结束
:20FFE00040F840F840F840F840F840F840F840F840F840F840F840F840F840F840F840F881
:00000001FF

🍅 HEX View 神器

  • HEX View 是一款专业的解析S19文件,HEX文件的工具,可以很方便的看出打开文件的Block块,起始地址和地址块的长度等信息

在这里插入图片描述

📙CAPL解析HEX文件源码


  • 核心变量解释下:

  • F_SegmentInfor[10]:用来存放解析HEX文件的Block的信息,一般情况下,刷写文件的地址是不连续的,那么就会分成几个Block块,每个Block块我们要记录下该Block起止地址数据大小,因为这是我们UDS 34服务下载的必须数据,这里定义数组大小为10,足够大了,具体有多少个Block块,由变量SegCounter记录

  • FlsData_BufferArr[0x1FFFFFF]: 这个数组是记录是HEX文件的所有字节,数组大小可由刷写文件具体大小设置,因为这个数组存放的是所有Block块的数据,那么当我下载的时候我怎么区分,去取数据呢,那就是 上面说的结构体中的 dword data_offset;这个变量来控制的,

  • AllDataBytes:该文件所有的数据字节数。

  • 我为什么没有这样定义 结构体呢?这样分段信息不是更加明确,刷写时取数据也更加方便直观吗?想一想为什么? struct FlsData_Segment
    {
    byte seg_index;
    dword start_address;
    dword data_size;
    byte FlsData_BufferArr[0x1FFFFFF];
    } F_SegmentInfor[10];//暂时定数组为10

  • Record type等于3/5的情况暂时没遇到,脚本没做处理。

/*@!Encoding:936*/variables
{ dword fileHandle;const dword  text_module = 0;const dword  binary_module = 1;enum File_Type { file_header, file_data,file_tail };struct  FlsData_Segment {byte  seg_index;dword start_address;dword data_size;dword data_offset;     } F_SegmentInfor[10];//暂时定数组为10long   SegCounter;       //记录文件被分成多少个段long   AllDataBytes;     // 文件所有的数据字节数byte  FlsData_BufferArr[0x1FFFFFF]; //文件中的所有字节被解析后放在该数组  
}on key 'a'
{Flash_Parse_HEX("E:\\merge.hex");}long Flash_Parse_Hex(char f_path[])
{long fileHandle;char tmpBuffer[256];                  //逐行读取,每行数据缓存dword   i;dword   tmpBufferByte;								//单块数据块字节数qword   OffsetAddress;								//扩展线性地址 	qword   ReAddr;												//上一数据行起始地址 dword   Len;													//HEX每行有效数据字节数dword   ReLen;												//HEX前一次数据长度dword   Addr;													//HEX每行起始地址dword   Type;		                      //HEX每行类型,有00,01,04四种类型long   file_line_num;    // 文件有多少行tmpBufferByte = 0;ReAddr = 0;ReLen = 0;SegCounter = 0;fileHandle = OpenFileRead(f_path,text_module);if (fileHandle == 0 ) {write("Failed to open File %s !",f_path);return 0 ;}write("File:%s Opened",f_path);while ( fileGetStringSZ(tmpBuffer,elcount(tmpBuffer),fileHandle)!=0 ){file_line_num++; //数据行计数器//write("file_line_num %d",file_line_num);//write("tmpBuffer %s",tmpBuffer);//判断首字符是否为:号if(tmpBuffer[0] == ':'){      Len = (char2byte(tmpBuffer[1])*0x10+char2byte(tmpBuffer[2])); // 数据长度Addr = char2byte(tmpBuffer[3])*0x1000+char2byte(tmpBuffer[4])*0x100+char2byte(tmpBuffer[5])*0x10+char2byte(tmpBuffer[6]);//偏移地址Addr = (OffsetAddress << 16) | Addr; //完整地址Type = char2byte(tmpBuffer[7])*0x10+char2byte(tmpBuffer[8]); //类型//以下为打印解析的过程,打印解析时候的变量// write("Addr %x",Addr);// write("tmpBufferByte %x",tmpBufferByte);switch(Type){case 0x00:											  //数据if (abs(Addr -ReAddr)  > ReLen ) //判断为新数据块{  if(tmpBufferByte == 0)			  //是否为首行数据字节数{ F_SegmentInfor[SegCounter].data_offset = 0;F_SegmentInfor[SegCounter].start_address = Addr;         //记录新数据块的起始地址}else										    //不是首行{F_SegmentInfor[SegCounter].data_size = tmpBufferByte; //数据长度 SegCounter++; tmpBufferByte = 0;					//重新开始计数F_SegmentInfor[SegCounter].start_address = Addr;		        //记录新数据块的起始地址F_SegmentInfor[SegCounter].data_offset += tmpBufferByte;		//相对数组FlsData_BufferArr的开始索引地址}}for(i = 0; i< Len ; i++){FlsData_BufferArr[AllDataBytes] = (char2byte(tmpBuffer[2*i+9])*0x10+char2byte(tmpBuffer[2*i+10]));AllDataBytes++;   //全文件的字节计数器tmpBufferByte ++ ;//当前block的计数器}  ReAddr = Addr;									//保存当前地址,下一次使用  ReLen  = Len;									  //保存当前长度,下一次使用   break;case 0x04:										   	//扩展线性地址记录OffsetAddress =  char2byte(tmpBuffer[9])*0x1000+char2byte(tmpBuffer[10])*0x100+char2byte(tmpBuffer[11])*0x10+char2byte(tmpBuffer[12]);		//偏移地址	 break;case 0x01:										   	//地址,结束 F_SegmentInfor[SegCounter].data_size = tmpBufferByte;        //数据长度F_SegmentInfor[SegCounter].data_offset = AllDataBytes - tmpBufferByte; //相对数组FlsData_BufferArr的开始索引地址 SegCounter++;break;          }        }}write("文件总行数:%d",file_line_num);write("文件总字节数:%d",AllDataBytes);write("文件总分段数:%d",SegCounter);for(i = 0; i < SegCounter; i++){write("数据块:%d,  起始地址:0x%X, 结束地址:0x%X, 数据长度:%6d字节\r\n", i+1, F_SegmentInfor[i].start_address, F_SegmentInfor[i].start_address + F_SegmentInfor[i].data_size - 1, F_SegmentInfor[i].data_size);}fileClose(fileHandle);return 1 ;
}byte char2byte(char ch)
{byte  val;val = 0;if ( ch >= '0' && ch <= '9'){val = ch - '0';      }if ( ch >= 'a' && ch <= 'f'){val = (ch - 'a') + 10;      }if ( ch >= 'A' && ch <= 'F'){val = (ch - 'A') + 10;       }return val;
}

  • CAPL脚本跑出来的结果和HexView对比,结果一致,说明我们解析没问题

在这里插入图片描述

在这里插入图片描述

🌎总结

23

7

  • 🚩要有最朴素的生活,最遥远的梦想,即使明天天寒地冻,路遥马亡!

  • 🚩如果这篇博客对你有帮助,请 “点赞” “评论”“收藏”一键三连 哦!码字不易,大家的支持就是我坚持下去的动力。
    18

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/642044.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

武汉大学博士,华为上班5年多,月薪多少。。。

最近&#xff0c;一位来自武汉大学的博士研究生透露了自己在华为公司工作五年后的薪酬情况。 据他透露&#xff0c;他在2018年加入华为时的月薪为2.4万&#xff0c;随着时间的推移&#xff0c;到了2023年&#xff0c;他的月薪已经增长至4.4万&#xff01;此外&#xff0c;他还透…

IntelliJ IDEA2020下使用Maven构建Scala 项目

1.创建maven文件 2.进入pom.xml导入依赖 <!--添加spark的依赖--><dependency><groupId>org.apache.spark</groupId><artifactId>spark-core_2.12</artifactId><version>3.2.1</version></dependency><!--添加scala依…

OpenHarmony开源鸿蒙NEXT星河版内核嵌入式编程

一、前景提要 2024年1月18日&#xff0c;华为放出HarmonyOS NEXT 鸿蒙星河版开发者预览版本&#xff08;不是HarmonyOS NEXT版&#xff0c;是HarmonyOS NEXT星河版&#xff09;&#xff0c;首次提到用鸿蒙内核&#xff08;暂命名&#xff09;取代了Linux内核。 该内核源码还未放…

电厂水泵远程自动化控制系统解决方案介绍

水泵将原动机的机械能或其他外部能量传送给液体&#xff0c;使液体能量增加&#xff0c;可以用于电力供水系统、城市供水系统、石油化工系统、农业水利系统等等行业&#xff0c;水泵远程自动化监测控制系统&#xff0c;可实时监测电厂水泵的运行状态&#xff0c;实现对水电厂排…

电力调度自动化中智能电网技术的应用

电力调度自动化中智能电网技术的应用 在现代电网的现代化发展和电网重组工作中起着关键作用,由于此项技术开发时间短,目前还没有形成一个相对清晰的概念,但此技术在未来的电网发展工作中的地位已得到了一些国家的认可。由于智能电网具有良好的兼容性以及交互性等优势,一经推出就…

XML OR MYsql 报错:Could not create connection to database server.

mybaits文件少复制了一个部分&#xff0c;或缺少部分&#xff1a; 添加至表头即可解决 代码&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE configuration SYSTEM "http://mybatis.org/dtd/mybatis-3-config.dtd" &g…

SpringMVC中的文件上传和中英文名称文件下载

一、文件上传 前端&#xff1a; <% page language"java" contentType"text/html;charsetUTF-8"pageEncoding"UTF-8"%> <! DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4…

【Elasticsearch】Elasticsearch 从入门到精通(一):基本介绍

《Elasticsearch 从入门到精通》共包含以下 2 2 2 篇文章&#xff1a; Elasticsearch 从入门到精通&#xff08;一&#xff09;&#xff1a;基本介绍Elasticsearch 从入门到精通&#xff08;二&#xff09;&#xff1a;基础使用 &#x1f60a; 如果您觉得这篇文章有用 ✔️ 的…

24V转2.8V2A降压芯片WT6030

24V转2.8V2A降压芯片WT6030 WT6030是一种高效同步整流降压开关模式转换器&#xff0c;集成内部功率MOSFET。该器件在宽输入电源范围内提供3A峰值输出电流&#xff0c;展现出卓越的负载和线路调节性能。其设计仅需要最小数量的外部现成组件&#xff0c;并且采用了节省空间的ESO…

【LeetCode热题100】【多维动态规划】最小路径和

题目链接&#xff1a;64. 最小路径和 - 力扣&#xff08;LeetCode&#xff09; 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 说明&#xff1a;每次只能向下或者向右移动一步。 经典动态规…

【行为型模型】迭代器模式

一、迭代器模式概述 迭代器模式定义&#xff1a;提供一种方法顺序访问一个聚合对象中的各个元素&#xff0c;而又不暴露其内部的表示。把游走的任务放在送代器上&#xff0c;而不是聚合上。这样简化了聚含的接口和实现,也让责任各得其所。(对象行为型) 迭代器模式的优缺点&…

等保测评之主机测评详解(二级)

等保测评之主机测评详解&#xff08;二级&#xff09;服务器——Windows 身份鉴别: 测评项a&#xff09;&#xff1a; a&#xff09;应对登录的用户进行身份标识和鉴别&#xff0c;身份标识具有唯一性&#xff0c;身份鉴别信息具有复杂度要求并定期更换&#xff1b; 整改方…