微处理器一般又称单片机,其可以根据人们编写的代码执行相关的逻辑操作。程序员将产品的逻辑操作抽象为C代码,然后通过编译器的编译和链接,生成微处理器可执行的机器码。通常编译器封装的不带调试信息的机器码有3种格式,分别为bin、motorola、hex,下面将分别介绍其特点:
1、Bin格式:
Bin文件是二进制文件,是编译器生成的机器码文件,烧录工具可以直接读取该文件的内容而不用解析,然后通过烧录口直接烧录到微处理器的程序空间,但烧录前要指定程序存储空间的起始地址。由于Bin文件不带文件内容校验功能,因此要注意其文件内容的破坏。
2、Motorola格式:
Motorola格式记录文件是ASCII格式的文件,又称SREC、S19,其是对机器码的一种封装描述。Motolora格式的文件相对于Bin文件来说,其带有程序的地址信息和数据校验功能,其Wiki的详细解说网址如下所示:
https://en.wikipedia.org/wiki/SREC_(file_format)
其数据组织方式为:
Record type | Byte count | Address | Data | Checksum |
Record type:
Record type为2个字节ASCII字符,第一个字符为‘S’,第二个字符为ASCII数字的‘0’~‘9’,下面将介绍其区别:
记录 类型 | 记录 目的 | 地址域 | 数据域 | 描述 |
S0 | 头说明 | 16位,默认值为“0000” | 有 | 本记录为供应商特定的ASCII字符串信息,通常该值默认为“HDR”。 |
S1 | 数据 | 16位地址 | 有 | 本记录包含了数据内容和其16位地址信息,适用于8位单片机。 |
S2 | 数据 | 24位地址 | 有 | 本记录包含了数据内容和其24位地址信息。 |
S3 | 数据 | 32位地址 | 有 | 本记录包含了数据内容和其32位地址信息,适用于32位芯片。 |
S4 | 保留 | N/A | N/A | 本记录保留,未定义 |
S5 | 计数 | 16位计数 | 无 | 本记录为可选记录,记录S1/S2/S3计数,当计数值大于0xFFFF,S6记录被使用 |
S6 | 计数 | 24位计数 | 无 | 本记录为可选记录,记录S1/S2/S3计数,当计数值小于0xFFFF,S5记录被使用 |
S7 | 起始地址或结束 | 32位地址 | 无 | 本记录用于定义32位可执行起始地址,也用于S3记录结束的标志。当SREC文件只是用于内存编程,则忽略起始地址。 |
S8 | 起始地址或结束 | 24位地址 | 无 | 本记录用于定义24位可执行起始地址,也用于S2记录结束的标志。当SREC文件只是用于内存编程,则忽略起始地址。 |
S9 | 起始地址或结束 | 16位地址 | 无 | 本记录用于定义16位可执行起始地址,也用于S1记录结束的标志。当SREC文件只是用于内存编程,则忽略起始地址。 |
对不同宽度的地址,其使用S19记录类型也不一样,对16位宽度的地址而言,其使用S0、S1、S5、S9类型的数据记录;对24位宽度的地址而言,其使用S0、S2、S5、S8类型的数据记录;对32位宽度的地址而言,其使用 S0、S3、S5、S7类型的数据记录。
Byte count:
Byte count为2个16进制的ASCII数字,定义了Address + Data + Checksum域字节总数目。
Address:
Address为4/6/8个16进制的ASCII数字,该个数取决于Record type的类型,用于表示数据的起始绝对地址,其数据格式为大端模式(即低地址为高字节数据)。
Data:
Data为2*n个16进制的ASCII数字(n字节数据)。
Checksum:
Checksum为2个16进制的ASCII数字,用于校验该行数据的完整性。该校验算法为将Byte count、Address、Data域的值进行相加,取低8位的和,然后取和的反值作为校验值,比如某S19文件中某记录为 S1090170E002FA050000A4,其数据和为:
09 + 01 + 70 + E0 + 02 + FA + 05 + 00 + 00 = 5B,5B的反值为A4,因此该行数据记录的校验值为A4。
S19数据记录以 行结束符 作为记录的结束,对不同的操作系统而言其行结束符是不一样的,比如对于Windows操作系统而言,其行结束符为CR LF(0x0D 0x0A)(‘\r’ ‘\n’),对于Linux操作系统而言,其行结束符为LF。
3、Hex格式:
Hex文件是ASCII格式的文件,其也是对机器码的一种封装描述。Hex格式的文件相对于Bin文件来说,其也是带有程序的地址信息和数据校验功能,其Wiki的解说网址如下所示:
https://en.wikipedia.org/wiki/Intel_HEX
其数据组织方式为:
Start code
| Byte Count | Address | Record type | Data | Checksum |
Start code:
Start code为1个ASCII字符’:’,用于标志一行Hex记录的开始。
Byte count:
Byte count为2个16进制的ASCII数字,定义Data域字节数目。
Address:
Address为4个16进制的ASCII数字,用于表示数据的偏移地址,其数据格式为大端模式(即低地址为高字节数据)。
Record type:
Record type为2个16进制的ASCII数字,其值范围为00 ~05,用于定义记录的类型。
Hex code | Record type | Description | Example |
00 | 数据(Data) | 包含了数据内容和其偏移地址 | :087DD00000A24A0400000000BB 本记录定义了偏移地址为0x7DD0的8个字节数据,分别为00,A2,4A,04,00,00,00,00
|
01 | 文件结束(End Of File) | 该记录为Hex文件的最后一个记录,用于标志Hex文件记录的结束,该记录的固定格式为::00000001FF | :00000001FF 本记录用于标志Hex文件记录的结束。 |
02 | 扩展分片地址(Extended Segment Address) | 该记录数据域定义了分片的基础地址,地址域为0x0000 | :020000021200EA |
03 | 分片起始地址(Start Segment Address) | 该行数据域定义了分片的起始地址,地址域为0x0000 | :0400000300003800C1 |
04 | 扩展线性地址(Extended Linear Address) | 该行数据域定义了随后分片数据地址的高16位地址,使用00 和 02数据记录可以计算出分片数据的绝对地址,该地址域为0x0000 | :02000004FFFFFC |
05 | 起始线性地址(Start Linear Address) | 该数据域定义了起始线性地址,该地址域为0x0000 | :04000005080060EDA2 |
对使用不同宽度地址而言,其使用Hex记录类型也不一样,对16位宽度的地址而言,其使用00和01类型的数据记录;对20位宽度的地址而言,其使用00、01、02、03类型的数据记录;对32位宽度的地址而言,其使用 00、01、04、05类型的数据记录。
Data:
Data为2*n个16进制的ASCII数字(n字节数据)。
Checksum:
Checksum为2个16进制的ASCII数字,用于校验该行数据的完整性。该校验算法为将Byte count、Address、Record type、Data域的值进行相加,取低8位的和,然后取和的互补值(取反加1)作为校验值,比如hex文件中某hex记录为 :020000040800F2,其数据和为:02 + 00 + 00 + 04 + 08 + 00 = 0E,0E的互补值为F2,因此该行数据记录的校验值为F2。
HEX数据记录以 行结束符 作为记录的结束,对不同的操作系统而言其行结束符是不一样的,比如对于Windows操作系统而言,其行结束符为CR LF(0x0D 0x0A)(‘\r’ ‘\n’),对于Linux操作系统而言,其行结束符为LF。
4、区别:
Bin格式、Motorola格式、Hex格式的区别如下表所示:
| Bin格式 | Motorola格式 | Hex格式 |
文件格式 | 二进制 | ASCII | ASCII |
文件大小 | 小 | 大 | 大 |
是否带有地址信息 | 无 | 有 | 有 |
程序地址格式 | 无 | 绝对地址 | 相对地址 |
内容校验 | 无 | 有 | 有 |
5、格式解析代码:
motorola和hex解析头文件为ProgramFileDecode.h,其内容如下所示:
#ifndef __PROGRAM_FILE_DECODE_H
#define __PROGRAM_FILE_DECODE_H
#define PROGRAM_ARGUMENT_ERROR (-1)
#define PROGRAM_UNKNOWN_CONTENT (-2)
#define PROGRAM_S19_RECORD_UNKNOWN_ERROR (-3)
#define PROGRAM_S19_RECORD_CHECKSUM_ERROR (-4)
#define PROGRAM_HEX_RECORD_UNKNOWN_ERROR (-3)
#define PROGRAM_HEX_RECORD_CHECKSUM_ERROR (-4)
#define PROGRAM_ADDRESS_OVERLAP_ERROR (-5)
#define SUPPORT_MAX_SEGMENT (100)
#define SUPPORT_SEGMENT_SIZE (0xFFFF)
typedef struct
{
uint8_t* data[SUPPORT_MAX_SEGMENT];
int dataLen[SUPPORT_MAX_SEGMENT];
uint32_t address[SUPPORT_MAX_SEGMENT];
int segmentNum;
}ProgramSegment;
typedef enum
{
START_OUT_END_OUT=0,
START_OUT_END_IN,
START_IN_END_IN,
START_IN_END_OUT,
START_OUT_END_OUT1
}ADDR_STATE;
extern ProgramSegment gProgramSegment;
int ProgramFileDecode(char *program,int programLen,uint32_t startAddress,uint32_t endAddress,ProgramSegment *segment);
#endif
其C文件内容如下所示:
#include <ansi_c.h>
#include "ProgramFileDecode.h"
int gS4_Error = 0;
uint8_t gU1_ProgramData[SUPPORT_MAX_SEGMENT * SUPPORT_SEGMENT_SIZE];
uint32_t gU4_ProgramDataUsedCnt = 0;//用于计数gU1_ProgramData的使用数目
char gU1_RecordArray[512];
uint32_t gU4_RecordArrayLen=0;
uint8_t gU1_RecordArrayBinValue[256];
uint8_t gU1_RecordData[256];
uint8_t gU1_RecordType=0,gU1_ByteCount = 0,gU1_DataLen = 0;
uint32_t gU4_AddressStart=0;
uint32_t gU4_AddressEnd=0;
uint32_t gU4_AddressEndLast=0;
ADDR_STATE addressState = START_OUT_END_OUT;
uint32_t gU4_IgnoreByteCnt=0;
uint32_t gU4_PaddingByteLen=0;
uint32_t gU4_ValidDataLen = 0;
uint32_t gU4_ProgramDataLen=0;
uint8_t gU1_MemoryBusWith = 1;
int gS4_AddressWidth = 1;
int gS4_EndLineCharType = 0;
int gS4_PaddingSwitch = 0;
int gU1_PaddingValue = 0xFF;
ProgramSegment gProgramSegment;
void ProgramDecodeModeSet(int addressWidth,int endLineCharType,int paddingSwitch,uint8_t paddingValue)
{
gS4_AddressWidth = addressWidth;
gS4_EndLineCharType = endLineCharType;
gS4_PaddingSwitch = paddingSwitch;
gU1_PaddingValue = paddingValue;
}
char *getARecord(char *str,char *record,unsigned int *recordLen)
{
char *pLF,*pCR;
size_t len=0;
if(((*str) == 'S') || ((*str) == ':'))
{
pLF = strchr(str,10);
pCR = pLF-1;
if((*pCR) == 13)
{
//Windows system
len = (size_t)(pCR - str);
strncpy(record,str,len);
}
else
{
//Linux system
len = (size_t)(pLF - str);
strncpy(record,str,len);
}
record[len]=0;
*recordLen = len;
return (++pLF);
}
else
return 0;
}
uint32_t getValueFromArray(uint8_t *data,int len)
{
int i;
uint32_t value=0;
if(len > 4)
return 0;
value = 0;
for(i=0;i<len;i++)
{
value = value * 256 + data[i];
}
return value;
}
int getBinValueFromHexAsciiArray(char *str,int len,uint8_t *data)
{
int i,j,byteCnt;
uint8_t hexValue=0;
byteCnt=len / 2;//字符串的长度必须为2的整数倍
hexValue=0;
for(j=0;j<byteCnt;j++)
{
hexValue = 0;
for(i=j*2;i<j*2+2;i++)
{
if(str[i] >= '0' && str[i] <= '9')
{
hexValue=hexValue * 16 + (str[i] - '0');
}
else if(str[i] >= 'a' && str[i] <= 'f')
{
hexValue=hexValue * 16 + (10 + str[i] - 'a');
}
else if(str[i] >= 'A' && str[i] <= 'F')
{
hexValue=hexValue * 16 + (10 + str[i] - 'A');
}
}
data[j]= hexValue;
}
return byteCnt;
}
int getMotorolaRecordInfo(char *record,int recordLen,uint8_t *recordType,uint8_t *byteCount,uint32_t *address,uint8_t *data,uint8_t *dataLen)
{
uint8_t type=0,byteCountTemp=0,addressAndCountLen=0;
uint8_t checkSumOrigion = 0,checkSumCal = 0;
uint8_t binValueArrayLen = 0;
int i;
if(record[0] == 'S')
{
type = record[1] - '0';
if(type > 9)
return PROGRAM_S19_RECORD_UNKNOWN_ERROR;
*recordType = type;
binValueArrayLen = (uint8_t)getBinValueFromHexAsciiArray(&record[2],recordLen - 2,gU1_RecordArrayBinValue);
byteCountTemp = gU1_RecordArrayBinValue[0];
if(byteCountTemp < 3)
return PROGRAM_S19_RECORD_UNKNOWN_ERROR;
*byteCount = byteCountTemp;
checkSumOrigion = (uint8_t)getValueFromArray(&gU1_RecordArrayBinValue[1 + byteCountTemp - 1],1);
checkSumCal = 0;
for(i=0;i<byteCountTemp;i++)
{
checkSumCal = checkSumCal + gU1_RecordArrayBinValue[i];
}
checkSumCal = ~checkSumCal;
if(checkSumCal != checkSumOrigion)
return PROGRAM_S19_RECORD_CHECKSUM_ERROR;
switch(type)
{
case 0:
addressAndCountLen = 2;
break;
case 1:
addressAndCountLen = 2;
break;
case 2:
addressAndCountLen = 3;
break;
case 3:
addressAndCountLen = 4;
break;
case 4:
//TODO return
break;
case 5:
addressAndCountLen = 2;
break;
case 6:
addressAndCountLen = 3;
break;
case 7:
addressAndCountLen = 4;
break;
case 8:
addressAndCountLen = 3;
break;
case 9:
addressAndCountLen = 2;
break;
default:
//TODO return
return PROGRAM_S19_RECORD_UNKNOWN_ERROR;
break;
}
*address = getValueFromArray(&gU1_RecordArrayBinValue[1],addressAndCountLen);
memcpy(data,&gU1_RecordArrayBinValue[1 + addressAndCountLen],byteCountTemp - addressAndCountLen -1);
*dataLen = binValueArrayLen - 2 - addressAndCountLen;
return 0;
}
else
{
return PROGRAM_S19_RECORD_UNKNOWN_ERROR;
}
}
int getHexRecordInfo(char *record,int recordLen,uint8_t *byteCount,uint32_t *address,uint8_t *recordType,uint8_t *data,uint8_t *dataLen)
{
uint8_t byteCountTemp=0;
uint8_t checkSumOrigion = 0,checkSumCal = 0;
int i;
if(record[0] == ':')
{
getBinValueFromHexAsciiArray(&record[1],recordLen - 1,gU1_RecordArrayBinValue);
byteCountTemp = (uint8_t)getValueFromArray(gU1_RecordArrayBinValue,1);
checkSumOrigion = (uint8_t)getValueFromArray(&gU1_RecordArrayBinValue[4 + byteCountTemp],1);
checkSumCal = 0;
for(i=0;i<(byteCountTemp + 4);i++)
{
checkSumCal = checkSumCal + gU1_RecordArrayBinValue[i];
}
checkSumCal = ~checkSumCal + 1;
if( checkSumCal != checkSumOrigion)
return PROGRAM_HEX_RECORD_CHECKSUM_ERROR;
*byteCount = byteCountTemp;
*dataLen = byteCountTemp;
*address = getValueFromArray(&gU1_RecordArrayBinValue[1],2);
*recordType = (uint8_t)getValueFromArray(&gU1_RecordArrayBinValue[3],1);
if(*recordType > 5)
return PROGRAM_HEX_RECORD_UNKNOWN_ERROR;
memcpy(data,&gU1_RecordArrayBinValue[4],byteCountTemp);
return 0;
}
else
{
return PROGRAM_HEX_RECORD_UNKNOWN_ERROR;
}
}
int ProgramFileDecode(char *program,int programLen,uint32_t startAddress,uint32_t endAddress,ProgramSegment *segment)
{
char *pNextRecord;
char *pEndRecord;
uint8_t *programData = NULL;
uint32_t programSegmentLen = 0;
uint32_t extendedLinearAddr = 0;
gS4_Error = 0;
if((program == NULL) || (startAddress >= endAddress) || (segment == NULL))
{
gS4_Error = PROGRAM_ARGUMENT_ERROR;
return gS4_Error;
}
pNextRecord = program;
pEndRecord = &program[programLen];
gU4_ProgramDataLen =0;
gU4_AddressEndLast = 0;
gU4_ValidDataLen = 0;
gU4_IgnoreByteCnt = 0;
extendedLinearAddr = 0;
while(pNextRecord < pEndRecord)
{
pNextRecord = getARecord(pNextRecord,gU1_RecordArray,&gU4_RecordArrayLen);
if(pNextRecord == 0)
{
break;
}
if(gU1_RecordArray[0] == 'S')
{
gS4_Error = getMotorolaRecordInfo(gU1_RecordArray,gU4_RecordArrayLen,&gU1_RecordType,&gU1_ByteCount,&gU4_AddressStart,gU1_RecordData,&gU1_DataLen);
if(gS4_Error < 0)
{
//Some error happend
return gS4_Error;
}
gU1_DataLen = gU1_DataLen / gU1_MemoryBusWith;
gU4_AddressEnd =gU4_AddressStart + gU1_DataLen - 1;
//Program data
switch(gU1_RecordType)
{
//Header
case 0:
break;
//Data
case 1:
case 2:
case 3:
if(gU4_AddressStart < startAddress)
{
if(gU4_AddressEnd < startAddress)
addressState = START_OUT_END_OUT;
else
addressState = START_OUT_END_IN;
}
else if(gU4_AddressStart <= endAddress)
{
if(gU4_AddressEnd <= endAddress)
addressState = START_IN_END_IN;
else
addressState = START_IN_END_OUT;
}
else if(gU4_AddressStart > endAddress)
{
addressState = START_OUT_END_OUT1;
}
switch(addressState)
{
case START_OUT_END_OUT:
gU4_IgnoreByteCnt = gU4_IgnoreByteCnt + gU1_DataLen;
break;
case START_OUT_END_IN:
gU4_ProgramDataUsedCnt = 0;
programSegmentLen = 0;
segment->segmentNum = 1;
segment->address[segment->segmentNum - 1] = startAddress;
segment->data[segment->segmentNum - 1] = &gU1_ProgramData[0];
programData = segment->data[segment->segmentNum - 1];
gU4_ValidDataLen = gU4_AddressEnd - startAddress + 1;
memcpy(&programData[0],&gU1_RecordData[(gU1_DataLen - gU4_ValidDataLen) * gU1_MemoryBusWith],gU4_ValidDataLen*gU1_MemoryBusWith);
programSegmentLen = gU4_ValidDataLen * gU1_MemoryBusWith;
segment->dataLen[segment->segmentNum - 1] = programSegmentLen;
gU4_AddressEndLast = gU4_AddressEnd;
break;
case START_IN_END_IN:
if(gU4_AddressEndLast == 0)//首个分片
{
gU4_ProgramDataUsedCnt = 0;
programSegmentLen = 0;
segment->segmentNum = 1;
segment->address[segment->segmentNum - 1] = startAddress;
segment->data[segment->segmentNum - 1] = &gU1_ProgramData[0];
programData = segment->data[segment->segmentNum - 1];
}
else if((gU4_AddressEndLast + 1) < gU4_AddressStart)//出现新的程序分片
{
gU4_ProgramDataUsedCnt = gU4_ProgramDataUsedCnt + programSegmentLen;
programSegmentLen = 0;
segment->segmentNum++;
segment->address[segment->segmentNum - 1] = gU4_AddressStart;
segment->data[segment->segmentNum - 1] = &gU1_ProgramData[gU4_ProgramDataUsedCnt];
programData = segment->data[segment->segmentNum - 1];
}
else if((gU4_AddressEndLast + 1) == gU4_AddressStart)//地址连续
{
}
else//出现错误,地址冲突
{
gS4_Error = PROGRAM_ADDRESS_OVERLAP_ERROR;
return gS4_Error;
}
gU4_ValidDataLen = gU1_DataLen;
memcpy(&programData[programSegmentLen],&gU1_RecordData[0],gU4_ValidDataLen*gU1_MemoryBusWith);
programSegmentLen = programSegmentLen + gU4_ValidDataLen * gU1_MemoryBusWith;
segment->dataLen[segment->segmentNum - 1] = programSegmentLen;
gU4_AddressEndLast = gU4_AddressEnd;
break;
case START_IN_END_OUT:
if(gU4_AddressEndLast == 0)//首个分片
{
gU4_ProgramDataUsedCnt = 0;
programSegmentLen = 0;
segment->segmentNum = 1;
segment->address[segment->segmentNum - 1] = startAddress;
segment->data[segment->segmentNum - 1] = &gU1_ProgramData[0];
programData = segment->data[segment->segmentNum - 1];
}
else if((gU4_AddressEndLast + 1) < gU4_AddressStart)//出现新的程序分片
{
gU4_ProgramDataUsedCnt = gU4_ProgramDataUsedCnt + segment->dataLen[segment->segmentNum - 1];
programSegmentLen = 0;
segment->segmentNum++;
segment->address[segment->segmentNum - 1] = gU4_AddressStart;
segment->data[segment->segmentNum - 1] = &gU1_ProgramData[gU4_ProgramDataUsedCnt];
programData = segment->data[segment->segmentNum - 1];
}
else if((gU4_AddressEndLast + 1) == gU4_AddressStart)//地址连续
{
}
else//出现错误,地址冲突
{
gS4_Error = PROGRAM_ADDRESS_OVERLAP_ERROR;
return gS4_Error;
}
gU4_ValidDataLen = endAddress - gU4_AddressStart + 1;
memcpy(&programData[programSegmentLen],&gU1_RecordData[0],gU4_ValidDataLen*gU1_MemoryBusWith);
programSegmentLen = programSegmentLen + gU4_ValidDataLen * gU1_MemoryBusWith;
segment->dataLen[segment->segmentNum - 1] = programSegmentLen;
gU4_ProgramDataUsedCnt = gU4_ProgramDataUsedCnt + programSegmentLen;
gU4_AddressEndLast = gU4_AddressEnd;
break;
case START_OUT_END_OUT1:
break;
default:
;
break;
}
break;
//Reserve
case 4:
break;
//Count
case 5:
case 6:
break;
//End flag
case 7:
case 8:
case 9:
break;
default:
;
}
}
else if(gU1_RecordArray[0] == ':')
{
gS4_Error = getHexRecordInfo(gU1_RecordArray,gU4_RecordArrayLen,&gU1_ByteCount,&gU4_AddressStart,&gU1_RecordType,gU1_RecordData,&gU1_DataLen);
if(gS4_Error < 0)
{
return gS4_Error;
}
switch(gU1_RecordType)
{
//Data
case 0:
gU4_AddressStart = gU4_AddressStart + extendedLinearAddr;
gU1_DataLen = gU1_DataLen / gU1_MemoryBusWith;
gU4_AddressEnd =gU4_AddressStart + gU1_DataLen - 1;
if(gU4_AddressStart < startAddress)
{
if(gU4_AddressEnd < startAddress)
addressState = START_OUT_END_OUT;
else
addressState = START_OUT_END_IN;
}
else if(gU4_AddressStart <= endAddress)
{
if(gU4_AddressEnd <= endAddress)
addressState = START_IN_END_IN;
else
addressState = START_IN_END_OUT;
}
else if(gU4_AddressStart > endAddress)
{
addressState = START_OUT_END_OUT1;
}
switch(addressState)
{
case START_OUT_END_OUT:
gU4_IgnoreByteCnt = gU4_IgnoreByteCnt + gU1_DataLen;
break;
case START_OUT_END_IN:
gU4_ProgramDataUsedCnt = 0;
programSegmentLen = 0;
segment->segmentNum = 1;
segment->address[segment->segmentNum - 1] = startAddress;
segment->data[segment->segmentNum - 1] = &gU1_ProgramData[0];
programData = segment->data[segment->segmentNum - 1];
gU4_ValidDataLen = gU4_AddressEnd - startAddress + 1;
memcpy(&programData[0],&gU1_RecordData[(gU1_DataLen - gU4_ValidDataLen) * gU1_MemoryBusWith],gU4_ValidDataLen*gU1_MemoryBusWith);
programSegmentLen = gU4_ValidDataLen * gU1_MemoryBusWith;
segment->dataLen[segment->segmentNum - 1] = programSegmentLen;
gU4_AddressEndLast = gU4_AddressEnd;
break;
case START_IN_END_IN:
if(gU4_AddressEndLast == 0)//首个分片
{
gU4_ProgramDataUsedCnt = 0;
programSegmentLen = 0;
segment->segmentNum = 1;
segment->address[segment->segmentNum - 1] = startAddress;
segment->data[segment->segmentNum - 1] = &gU1_ProgramData[0];
programData = segment->data[segment->segmentNum - 1];
}
else if((gU4_AddressEndLast + 1) < gU4_AddressStart)//出现新的程序分片
{
gU4_ProgramDataUsedCnt = gU4_ProgramDataUsedCnt + segment->dataLen[segment->segmentNum - 1];
programSegmentLen = 0;
segment->segmentNum++;
segment->address[segment->segmentNum - 1] = gU4_AddressStart;
segment->data[segment->segmentNum - 1] = &gU1_ProgramData[gU4_ProgramDataUsedCnt];
programData = segment->data[segment->segmentNum - 1];
}
else if((gU4_AddressEndLast + 1) == gU4_AddressStart)//地址连续
{
}
else//出现错误,地址冲突
{
gS4_Error = PROGRAM_ADDRESS_OVERLAP_ERROR;
return gS4_Error;
}
gU4_ValidDataLen = gU1_DataLen;
memcpy(&programData[programSegmentLen],&gU1_RecordData[0],gU4_ValidDataLen*gU1_MemoryBusWith);
programSegmentLen = programSegmentLen + gU4_ValidDataLen * gU1_MemoryBusWith;
segment->dataLen[segment->segmentNum - 1] = programSegmentLen;
gU4_AddressEndLast = gU4_AddressEnd;
break;
case START_IN_END_OUT:
if(gU4_AddressEndLast == 0)//首个分片
{
gU4_ProgramDataUsedCnt = 0;
programSegmentLen = 0;
segment->segmentNum = 1;
segment->address[segment->segmentNum - 1] = startAddress;
segment->data[segment->segmentNum - 1] = &gU1_ProgramData[0];
programData = segment->data[segment->segmentNum - 1];
}
else if((gU4_AddressEndLast + 1) < gU4_AddressStart)//出现新的程序分片
{
gU4_ProgramDataUsedCnt = gU4_ProgramDataUsedCnt + segment->dataLen[segment->segmentNum - 1];
programSegmentLen = 0;
segment->segmentNum++;
segment->address[segment->segmentNum - 1] = gU4_AddressStart;
segment->data[segment->segmentNum - 1] = &gU1_ProgramData[gU4_ProgramDataUsedCnt];
programData = segment->data[segment->segmentNum - 1];
}
else if((gU4_AddressEndLast + 1) == gU4_AddressStart)//地址连续
{
}
else//出现错误,地址冲突
{
gS4_Error = PROGRAM_ADDRESS_OVERLAP_ERROR;
return gS4_Error;
}
gU4_ValidDataLen = endAddress - gU4_AddressStart + 1;
memcpy(&programData[programSegmentLen],&gU1_RecordData[0],gU4_ValidDataLen*gU1_MemoryBusWith);
programSegmentLen = programSegmentLen + gU4_ValidDataLen * gU1_MemoryBusWith;
segment->dataLen[segment->segmentNum - 1] = programSegmentLen;
gU4_AddressEndLast = gU4_AddressEnd;
break;
case START_OUT_END_OUT1:
break;
default:
;
break;
}
break;
//End of file
case 1:
break;
//Extended segment address
case 2:
break;
//Start segment address
case 3:
break;
//Extended linear address
case 4:
extendedLinearAddr = ((gU1_RecordData[0] << 8) & 0xFF00) | (gU1_RecordData[1]);
extendedLinearAddr = (extendedLinearAddr << 16) & 0xFFFF0000;
break;
//Start linear address
case 5:
break;
default:
;
}
}
else
{
gS4_Error = PROGRAM_UNKNOWN_CONTENT;
return gS4_Error;
}
}
return 0;
}
代码讲解:
Motorola和Hex程序文件解析函数入口为ProgramFileDecode,其函数原型如下所示:
int ProgramFileDecode(char *program,int programLen,uint32_t startAddress,uint32_t endAddress,ProgramSegment *segment);
其中program为从程序文件中读取出来的文件内容,programLen为文件内容的长度,startAddress为需要截取程序的起始地址,endAddress为需要截取程序的终止地址,segment为起始地址和结束地址之间的程序分片。当调用ProgramFileDecode函数成功后,需要将segment分片的内容打包发给微处理器的Bootloader以更新程序。
代码举例:
int ProgramFileProcess(void)
{
int n;
ssize_t size;
int fileHandle = 0;
int ret = 0;
int k = 0;
n = GetFileInfo(programFilePath,&size);
fileHandle = OpenFile(programFilePath,VAL_READ_ONLY,VAL_OPEN_AS_IS,VAL_BINARY );
ret = ReadFile(fileHandle,hexFileContent,size);
if(ret != size)
{
DebugInfo(LEVEL_ERROR,"Read program file failed\r\n");
}
ProgramFileDecode(hexFileContent,size,gU4_FlashStartAddr,gU4_FlashEndAddr,&gProgramSegment);
GetPageAddress(gProgramSegment.address[0],gU4_FlashPageSize,&gU4_ProgramStartPageAddress);
GetPageAddress(gProgramSegment.address[gProgramSegment.segmentNum - 1] + gProgramSegment.dataLen[gProgramSegment.segmentNum - 1],gU4_FlashPageSize,&gU4_ProgramEndPageAddress);
gU4_ProgramEndPageAddress = gU4_ProgramEndPageAddress + gU4_FlashPageSize - 1;
//DebugInfo(LEVEL_NORMAL,"StartPageAddress = 0x%X,EndPageAddress = 0x%X\r\n",gU4_ProgramStartPageAddress,gU4_ProgramEndPageAddress);
if(gProgramSegment.address[0] != gU4_ProgramStartPageAddress)
{
DebugInfo(LEVEL_WARNING,"Attention!.Program start address is not page address.\r\n");
}
ProgramUpgrade1(&programUpgradeCancel);
return 0;
}