I've done it several times now.
But the first time in PureBASIC.
IntelHex.pbi
Code: Select all
;
; IntelHex include file V1.01
;
; if ExtendedSegmentAddresseRecords (02) is set to #True, than
; this type is used instead of ExtendedLinearAddressRecords (04)
; when creating large hex files
;
Enumeration
#INTELHEX_NOT_ABLE_TO_LOAD_FILE = 1
#INTELHEX_NOT_ABLE_TO_WRITE_FILE
#INTELHEX_UNABLE_TO_ALLOCATE_MEMORY
#INTELHEX_ADDRESS_OUT_OF_RANGE
#INTELHEX_CHECKSUM_WRONG
EndEnumeration
Enumeration
#INTELHEX_DataRecord
#INTELHEX_EndOfFileRecord
#INTELHEX_ExtendedSegmentAddressRecord
#INTELHEX_StartSegmentAddressRecord
#INTELHEX_ExtendedLinearAddressRecord
#INTELHEX_StartLinearAddressRecord
EndEnumeration
Structure IntelHexFileStr
HexFilename$
BinFilename$
BufferSize.l
*Buffer
StartAddress.l
EndAddress.l
Offset.l
ExtendedSegmentAddressesRecords.a
Error.i
ErrorLine.i
EndStructure
Procedure.s IntelHexError(*Info.IntelHexFileStr)
Result$ = ""
Select *Info\Error
Case #INTELHEX_NOT_ABLE_TO_LOAD_FILE
Result$ = "Not able to open the file"
Case #INTELHEX_NOT_ABLE_TO_WRITE_FILE
Result$ = "Not able to create the file"
Case #INTELHEX_UNABLE_TO_ALLOCATE_MEMORY
Result$ = "Unabel to allocate memory"
Case #INTELHEX_ADDRESS_OUT_OF_RANGE
Result$ = "Address is larger than the buffer size (" + Str(*Info\BufferSize) + ") in line " + Str(*Info\ErrorLine)
Case #INTELHEX_CHECKSUM_WRONG
Result$ = "Wrong checksum in line " + Str(*Info\ErrorLine)
EndSelect
ProcedureReturn Result$
EndProcedure
Procedure.a IntelHexCalcChecksum(Line$)
Length = (Len(Line$) - 3) >> 1
Checksum.a = 0
For i = 0 To Length - 1
Checksum + Val("$" + Mid(Line$, 2 + i * 2, 2))
Next i
ProcedureReturn ~Checksum + 1
EndProcedure
Procedure IntelHexDecodeLine(*Info.IntelHexFileStr, Line$)
If Left(Line$, 1) = ":"
If IntelHexCalcChecksum(Line$) = Val("$" + Right(Line$, 2))
Type = Val("$" + Mid(Line$, 8, 2))
Select Type
Case #INTELHEX_DataRecord
Length = Val("$" + Mid(Line$, 2, 2))
Start = *Info\Offset + Val("$" + Mid(Line$, 4, 4))
If Start + Length <= *Info\BufferSize
For i = 1 To Length
PokeA(*Info\Buffer + Start + (i - 1), Val("$" + Mid(Line$, 8 + i * 2, 2)))
Next i
If *Info\StartAddress > Start : *Info\StartAddress = Start : EndIf
If *Info\EndAddress < (Start + Length) : *Info\EndAddress = Start + Length : EndIf
Else
*Info\Error = #INTELHEX_ADDRESS_OUT_OF_RANGE
EndIf
Case #INTELHEX_EndOfFileRecord
; no need to detect it
Case #INTELHEX_ExtendedSegmentAddressRecord
*Info\Offset = Val("$" + Mid(Line$, 10, 4)) << 4
Debug Hex(*Info\Offset)
Case #INTELHEX_StartSegmentAddressRecord
; no need for CS:IP here (start address for X86)
Case #INTELHEX_ExtendedLinearAddressRecord
*Info\Offset = Val("$" + Mid(Line$, 10, 4)) << 16
Case #INTELHEX_StartLinearAddressRecord
; no need for EIP here (start address for X86 protected mode)
EndSelect
Else
*Info\Error = #INTELHEX_CHECKSUM_WRONG
EndIf
EndIf
EndProcedure
Procedure IntelHexLoadHexFile(*Info.IntelHexFileStr)
*Info\StartAddress = *Info\BufferSize
*Info\Offset = 0
*Info\EndAddress = 0
*Info\Error = 0
*Info\ErrorLine = 0
If ReadFile(0, *Info\HexFilename$)
If *Info\Buffer : FreeMemory(*Info\Buffer) : EndIf
*Info\Buffer = AllocateMemory(*Info\BufferSize)
If *Info\Buffer
LineNo = 0
While Not Eof(0) And Not *Info\Error
LineNo + 1
IntelHexDecodeLine(*Info, ReadString(0))
Wend
If *Info\Error : *Info\ErrorLine = LineNo : EndIf
Else
*Info\Error = #INTELHEX_UNABLE_TO_ALLOCATE_MEMORY
EndIf
CloseFile(0)
Else
*Info\Error = #INTELHEX_NOT_ABLE_TO_LOAD_FILE
EndIf
ProcedureReturn *Info\Error
EndProcedure
Procedure IntelHexLoadBinFile(*Info.IntelHexFileStr)
*Info\Error = 0
If ReadFile(0, *Info\BinFilename$)
*Info\BufferSize = Lof(0)
If *Info\Buffer : FreeMemory(*Info\Buffer) : EndIf
*Info\Buffer = AllocateMemory(*Info\BufferSize)
If *Info\Buffer
If ReadData(0, *Info\Buffer, *Info\BufferSize) = *Info\BufferSize
*Info\StartAddress = 0
*Info\EndAddress = *Info\BufferSize
EndIf
Else
*Info\Error = #INTELHEX_UNABLE_TO_ALLOCATE_MEMORY
EndIf
CloseFile(0)
Else
*Info\Error = #INTELHEX_NOT_ABLE_TO_LOAD_FILE
EndIf
ProcedureReturn *Info\Error
EndProcedure
Procedure.s IntelHexEncodeBytes(*Ptr, Index, Length)
Line$ = ":"
Line$ + RSet(Hex(Length), 2, "0")
Line$ + RSet(Hex(Index & $FFFF), 4, "0")
Line$ + "00"
CalculatedChecksum.a = Length + (Index >> 8) + (Index & $FF)
For i = 0 To Length - 1
Byte = PeekA(*Ptr + Index + i)
Line$ + RSet(Hex(Byte), 2, "0")
CalculatedChecksum + Byte
Next i
CalculatedChecksum = ~CalculatedChecksum + 1
Line$ + RSet(Hex(CalculatedChecksum), 2, "0")
ProcedureReturn Line$
EndProcedure
Procedure IntelHexWriteHexFile(*Info.IntelHexFileStr)
If CreateFile(0, *Info\HexFilename$)
Offset.l = 0
Help.l = (*Info\EndAddress & $FFFFFFF0) - 1
For i = *Info\StartAddress To Help Step 16
If i >> 16 > Offset
Offset = i >> 16
If *Info\ExtendedSegmentAddressesRecords
HelpLine$ = ":02000002" + RSet(Hex(Offset << 12), 4, "0") + "00"
Else
HelpLine$ = ":02000004" + RSet(Hex(Offset), 4, "0") + "00"
EndIf
HelpLine$ = Left(HelpLine$, 13) + RSet(Hex(IntelHexCalcChecksum(HelpLine$)), 2, "0")
WriteStringN(0, HelpLine$)
EndIf
WriteStringN(0, IntelHexEncodeBytes(*Info\Buffer, i, 16))
Next i
If i < *Info\EndAddress
WriteStringN(0, IntelHexEncodeBytes(*Info\Buffer, i, *Info\EndAddress - i))
EndIf
WriteStringN(0, ":00000001FF")
CloseFile(0)
Else
*Info\Error = #INTELHEX_NOT_ABLE_TO_WRITE_FILE
EndIf
ProcedureReturn *Info\Error
EndProcedure
Procedure IntelHexWriteBinFile(*Info.IntelHexFileStr)
If CreateFile(0, *Info\BinFilename$)
WriteData(0, *Info\Buffer, *Info\EndAddress)
CloseFile(0)
Else
*Info\Error = #INTELHEX_NOT_ABLE_TO_WRITE_FILE
EndIf
ProcedureReturn *Info\Error
EndProcedure
Procedure IntelHexWriteFile(*Info.IntelHexFileStr)
Result = 0
If *Info\HexFilename$
If *Info\BinFilename$ = ""
*Info\BinFilename$ = Left(*Info\HexFilename$, FindString(*Info\HexFilename$, ".hex", 1)) + "bin"
EndIf
Result = IntelHexWriteBinFile(*Info)
ElseIf *Info\BinFilename$
If *Info\HexFilename$ = ""
*Info\HexFilename$ = Left(*Info\BinFilename$, FindString(*Info\BinFilename$, ".bin", 1)) + "hex"
EndIf
Result = IntelHexWriteHexFile(*Info)
EndIf
ProcedureReturn Result
EndProcedure
Procedure IntelHexLoadFile(*Info.IntelHexFileStr)
*Info\Error = #INTELHEX_NOT_ABLE_TO_LOAD_FILE
If *Info\HexFilename$
If *Info\BufferSize = 0 : *Info\BufferSize = 64 * 1024 : EndIf
IntelHexLoadHexFile(*Info)
ElseIf *Info\BinFilename$
IntelHexLoadBinFile(*Info)
EndIf
ProcedureReturn *Info\Error
EndProcedure
Code: Select all
IncludeFile "IntelHex.pbi"
Procedure Usage()
PrintN("")
PrintN(" Hexer V1.00")
PrintN("")
PrintN(" usage: Hexer file [buffer size]")
PrintN("")
PrintN(" file : *.hex or *.bin")
PrintN(" buffer size: only for hex files (default is 65536)")
PrintN("")
EndProcedure
Info.IntelHexFileStr
OpenConsole()
If CountProgramParameters() > 0
Filename$ = ProgramParameter(0)
If FindString(Filename$, ".hex", 1)
Info\HexFilename$ = Filename$
If CountProgramParameters() = 2
Info\BufferSize = Val(ProgramParameter(1))
EndIf
ElseIf FindString(Filename$, ".bin", 1)
Info\BinFilename$ = Filename$
EndIf
If IntelHexLoadFile(@Info) = 0
IntelHexWriteFile(@Info)
EndIf
If Info\Error
PrintN(IntelHexError(@Info))
EndIf
Else
Usage()
EndIf

Best regards,
Bernd