diff options
Diffstat (limited to 'host/utils/ihexcvt.cpp')
-rw-r--r-- | host/utils/ihexcvt.cpp | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/host/utils/ihexcvt.cpp b/host/utils/ihexcvt.cpp new file mode 100644 index 000000000..0605ee61c --- /dev/null +++ b/host/utils/ihexcvt.cpp @@ -0,0 +1,250 @@ +/* IHexCvt - Intel HEX File <=> Binary Converter (C++) + Copyright (C) 2014 Ali Nakisaee + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.*/ + +//Include needed stuff from C++ +#include <iostream> +#include <fstream> +#include <string> + +//... and also from C +#include <stdio.h> + +#include <boost/filesystem.hpp> + +#include <uhd/exception.hpp> +#include "ihexcvt.hpp" + +//Avoid repeating 'std::': +using namespace std; + +//The following function reads a hexadecimal number from a text file. +template <class T> +static bool ReadValueFromHex(ifstream& InputFile, T& outCh, unsigned char* ApplyChecksum) +{ + char V, L; + T X = 0; + outCh = 0; + + //Get the characters one by one. + //Remember: These values are big-endian. + //Remember: Every two hex characters (0-9/A-F) indicate ONE byte. + for (size_t i = 0; i < 2 * sizeof(T); i++) + { + InputFile.get( V ); + if (InputFile.fail()) + return false; + + X <<= 4; + if (V >= '0' && V <= '9') + L = (V - '0'); + else if (V >= 'a' && V <= 'f') + L = (V - 'a' + 10); + else if (V >= 'A' && V <= 'F') + L = (V - 'A' + 10); + else + return false; + X |= L; + + //Apply this character to the checksum + if (ApplyChecksum && i % 2 == 1) *ApplyChecksum += X & 0xFF; + } + + //Return... + outCh = X; + return true; +} + +//The following function writes a hexadecimal number from a text file. +template <class T> +static bool WriteHexValue(ofstream& OutFile, T Value, unsigned char* CalcChecksum) +{ + unsigned char V0 = 0; + char C; + + //Remember: These values are big-endian. + for (size_t i = 0; i < sizeof(T); i++) + { + //Get byte #i from the value. + V0 = (Value >> ((sizeof(T) - i - 1) * 8)) & 0xFF; + + //Extract the high nibble (4-bits) + if ((V0 & 0xF0) <= 0x90) + C = (V0 >> 4) + '0'; + else + C = (V0 >> 4) + ('A' - 10); + OutFile.put( C ); + + //Extract the low nibble (4-bits) + if ((V0 & 0xF) <= 0x9) + C = (V0 & 0xF) + '0'; + else + C = (V0 & 0xF) + ('A' - 10); + OutFile.put( C ); + + //Calculate the checksum + if (CalcChecksum) *CalcChecksum += V0; + } + return true; +} + +//Skip any incoming whitespaces +static void SkipWhitespace(ifstream& InputFile) +{ + for (;;) + { + char C; + InputFile.get(C); + if (InputFile.eof() || InputFile.fail()) break; + if (!(C == '\n' || C == '\r' || C == ' ' || C == '\t' || C == '\v')) + { + InputFile.putback(C); + break; + } + } +} + +//The function responsible for conversion from HEX files to BINary. +void Hex2Bin(const char* SrcName, const char* DstName, bool IgnoreChecksum) +{ + ifstream Src(SrcName); + if (Src.bad()) + { + throw uhd::runtime_error("Could not convert Intel .hex file to binary."); + } + + ofstream Dst(DstName, ios_base::binary); + if (Dst.bad()) + { + throw uhd::runtime_error("Could not convert Intel .hex file to binary."); + } + + char Ch; + int LineIdx = 1; + + unsigned char ByteCount; + unsigned short AddressLow; + unsigned short Extra; + unsigned long ExtraL; + unsigned long AddressOffset = 0; + unsigned char RecordType; + unsigned char Data[255]; + unsigned char CurChecksum; + unsigned char FileChecksum; + bool EOFMarker = false; + bool EOFWarn = false; + + for ( ;; ) + { + Src.get(Ch); + if (Src.eof()) + break; + if (EOFMarker && !EOFWarn) + { + throw uhd::runtime_error("Could not convert Intel .hex file to binary."); + } + if (Ch != ':') goto genericErr; + + CurChecksum = 0; + if (!ReadValueFromHex( Src, ByteCount, &CurChecksum )) goto genericErr; + if (!ReadValueFromHex( Src, AddressLow, &CurChecksum )) goto genericErr; + if (!ReadValueFromHex( Src, RecordType, &CurChecksum )) goto genericErr; + + switch (RecordType) + { + case 0x00: //Data record + for (int i = 0; i < ByteCount; i++) + if (!ReadValueFromHex( Src, Data[i], &CurChecksum )) goto genericErr; + break; + case 0x01: //End Marker + if ( ByteCount != 0 ) + { + goto onErrExit; + } + EOFMarker = true; + break; + case 0x02: //Extended Segment Address + if ( ByteCount != 2 || AddressLow != 0 ) + { + goto onErrExit; + } + if (!ReadValueFromHex( Src, Extra, &CurChecksum )) goto genericErr; + AddressOffset = (unsigned long)Extra << 4; + break; + case 0x03: //Start Segment Address + if ( ByteCount != 4 || AddressLow != 0 ) + { + goto onErrExit; + } + if (!ReadValueFromHex( Src, ExtraL, &CurChecksum )) goto genericErr; + break; + case 0x04: //Extended Linear Address + if ( ByteCount != 2 || AddressLow != 0 ) + { + goto onErrExit; + } + if (!ReadValueFromHex( Src, Extra, &CurChecksum )) goto genericErr; + AddressOffset = (unsigned long)Extra << 16; + break; + case 0x05: //Start Linear Address + if ( ByteCount != 4 || AddressLow != 0 ) + { + goto onErrExit; + } + if (!ReadValueFromHex( Src, ExtraL, &CurChecksum )) goto genericErr; + break; + } + + //Verify checksum + CurChecksum = (~(CurChecksum & 0xFF) + 1) & 0xFF; + if (!ReadValueFromHex( Src, FileChecksum, NULL )) goto genericErr; + if (CurChecksum != FileChecksum) + { + if (!IgnoreChecksum) goto onErrExit; + } + + //Put Data + if (RecordType == 0x00) + { + Dst.seekp( AddressLow + AddressOffset ); + for (int i = 0; i < ByteCount; i++) + { + Dst.put( Data[i] ); + } + } + + //Skip any white space + SkipWhitespace( Src ); + + LineIdx++; + } + + Dst << flush; + Dst.close(); + + return; + +genericErr: + throw uhd::runtime_error("Invalid Intel .hex file detected."); + +onErrExit: + Dst.close(); + Src.close(); + boost::filesystem::remove(DstName); + throw uhd::runtime_error("Could not convert Intel .hex file to binary."); +} |