最近在學習CAPL編程,簡單的操作基本掌握了。其實CAPL就是C語言的簡化版本,少了挺多特性的。剛開始上手有點不太懂,後面看了幾個別人的實例後就手癢癢想動手做點什麼。剛好在工作上遇到一些問題,想要用CAPL編寫一個UDS刷寫器。但是網上只能找到S19文件讀寫的例子。而我們的固件都是HEX文件的。那麼我就動手做了一個HEX文件解析器。
首先用Excel打開一個hex文件,通過分列很容易就能得到我的HEX文件裏面只有00,01,04三種碼。那麼我們在解析的時候只需要對這三種不同狀態的進行不同的解析即可。
接下來就是對進行編程了,首先創建一個Block的結構體,根據經驗我們知道,一個數據塊有:開始的地址,數據的長度,以及數據Buffer。三個結果。而一個hex文件裏面可能有多個數據塊,因此我們接下來聲明瞭5個數據塊。這個需要根據變量進行調整。然後根據hex文件初始化數據塊的個數。再聲明變量 HexBlockTotalNumber 爲數據塊的總數。
variables
{
struct Block {
dword BlockStartAddr; //數據開始的地址
dword BlockDataLength; //數據的長度
byte dataBuffer[0x020FFFF]; //數據區域(單塊數據的Buffer,如果hex文件很大,則需要把次參數調大)
};
struct Block hexfile[5]; //創建5個數據塊(主要根據HEX文件進行調整,hex有幾個數據塊就需要設置幾個)
int HexBlockTotalNumber = 0; //數據塊總數
dword t1; //計算解析所用的時間
}
/*********************************************************************************
*Function: //char2byte
* Description: //把單個字符轉換爲Byte的函數
*Input: //ch:ASCII編碼字符,取值爲0到F
*Return: //val,爲byte類型
**********************************************************************************/
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;
}
/*********************************************************************************
*Function: //Read_hexFile
* Description: //解碼HEX文件,只支持0x00,0x04,0x01類型
*Input: //Filename:需要解碼的文件名
*Output: //hexfile
*Return: //void
**********************************************************************************/
//讀取HEXFILE
void Read_hexFile(char Filename[])
{
long file_handle;
char RowData[128]; //逐行讀取,每行數據緩存,當每行數據大於128時,需要將其調整
dword i;
dword RowDataByte; //單塊數據塊字節數
qword OffsetAddress; //擴展線性地址
qword ReAddr; //上一數據行起始地址
dword Len; //HEX每行有效數據字節數
dword ReLen; //HEX前一次數據長度
dword Addr; //HEX每行起始地址
dword Type; //HEX每行類型,有00,01,04四種類型
RowDataByte = 0;i = 0;Len = 0;ReLen = 0;Addr=0;Type = 0;ReAddr = 0;
file_handle = OpenFileRead(Filename,0);
HexBlockTotalNumber = 0;
if(file_handle!=0)
{ // Read all lines
while ( fileGetStringSZ(RowData,elcount(RowData),file_handle)!=0 ){
//判斷首字符是否爲:號
if(RowData[0] == ':'){
Len = (char2byte(RowData[1])*0x10+char2byte(RowData[2]));
Addr = char2byte(RowData[3])*0x1000+char2byte(RowData[4])*0x100+char2byte(RowData[5])*0x10+char2byte(RowData[6]);
Addr |= (OffsetAddress << 16);
Type = char2byte(RowData[7])*0x10+char2byte(RowData[8]);
//以下爲打印解析的過程,打印解析時候的變量
//write("RowData:%s,HexBlockTotalNumber:%d,ReLen:%X,ReAddr:%X,Addr:%X,RowDataByte:%X",RowData,HexBlockTotalNumber,ReLen,ReAddr,Addr,RowDataByte);
switch(Type){
case 0x00: //數據
if (Addr > (ReLen + ReAddr)){ //判斷爲新數據塊
if(RowDataByte == 0) //是否爲首行數據字節數
{
hexfile[HexBlockTotalNumber].BlockStartAddr = Addr; //記錄新數據塊的起始地址
}
else //不是首行
{
hexfile[HexBlockTotalNumber].BlockDataLength = RowDataByte; //數據長度
RowDataByte = 0; //重新開始計數
hexfile[HexBlockTotalNumber].BlockStartAddr = Addr; //記錄新數據塊的起始地址
HexBlockTotalNumber++;
}
}
for(i = 0; i< Len ; i++)
{
//儲存buffer,注意沒有對crc進行校驗。
hexfile[HexBlockTotalNumber].dataBuffer[RowDataByte++]=(char2byte(RowData[2*i+9])*0x10+char2byte(RowData[2*i+10]));
}
ReAddr = Addr; //保存當前地址,下一次使用
ReLen = Len; //保存當前長度,下一次使用
break;
case 0x04: //擴展線性地址記錄
OffsetAddress = char2byte(RowData[9])*0x1000+char2byte(RowData[10])*0x100+char2byte(RowData[11])*0x10+char2byte(RowData[12]); //偏移地址
break;
case 0x01: //地址,結束
hexfile[HexBlockTotalNumber].BlockDataLength = RowDataByte; //數據長度
HexBlockTotalNumber++;
break;
}
}
}
write("Hex文件讀取成功, 數據分塊:%d",HexBlockTotalNumber);
for(i = 0; i < HexBlockTotalNumber; i++)
{
write("數據塊:%d, 起始地址:0x%X, 結束地址:0x%X, 數據長度:%6d字節\r\n", i+1, hexfile[i].BlockStartAddr, hexfile[i].BlockStartAddr + hexfile[i].BlockDataLength - 1, hexfile[i].BlockDataLength);
}
fileClose(file_handle);
}
else{
write("OpenFileRead,error occurs");
}
}
on key 'f'
{
t1 = timeNow();
Read_hexFile("test.hex");
write("%d",t1-timeNow());
write(hexfile[0].dataBuffer);
}
write (byte v[]) {
int i;
for (i=0; i<48; i++) write("dataBuffer:%x",hexfile[0].dataBuffer[i]);
}