diff options
Diffstat (limited to 'host')
| -rw-r--r-- | host/lib/usrp_clock/octoclock/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/ihexcvt.cpp | 250 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/ihexcvt.hpp | 22 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/kk_ihex.h | 191 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/kk_ihex_license.txt | 20 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/kk_ihex_read.c | 261 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/kk_ihex_read.h | 119 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp | 54 | ||||
| -rw-r--r-- | host/utils/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | host/utils/ihexcvt.cpp | 250 | ||||
| -rw-r--r-- | host/utils/ihexcvt.hpp | 22 | ||||
| -rw-r--r-- | host/utils/octoclock_firmware_burner.cpp | 23 | 
12 files changed, 655 insertions, 565 deletions
| diff --git a/host/lib/usrp_clock/octoclock/CMakeLists.txt b/host/lib/usrp_clock/octoclock/CMakeLists.txt index 96b670115..a74cb034f 100644 --- a/host/lib/usrp_clock/octoclock/CMakeLists.txt +++ b/host/lib/usrp_clock/octoclock/CMakeLists.txt @@ -21,8 +21,10 @@  LIBUHD_REGISTER_COMPONENT("OctoClock" ENABLE_OCTOCLOCK ON "ENABLE_LIBUHD" OFF OFF)  IF(ENABLE_OCTOCLOCK) +    ADD_DEFINITIONS(-DIHEX_USE_STDBOOL) +      LIBUHD_APPEND_SOURCES( -        ${CMAKE_CURRENT_SOURCE_DIR}/ihexcvt.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/kk_ihex_read.c          ${CMAKE_CURRENT_SOURCE_DIR}/octoclock_eeprom.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/octoclock_image_loader.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/octoclock_impl.cpp diff --git a/host/lib/usrp_clock/octoclock/ihexcvt.cpp b/host/lib/usrp_clock/octoclock/ihexcvt.cpp deleted file mode 100644 index 0605ee61c..000000000 --- a/host/lib/usrp_clock/octoclock/ihexcvt.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/*  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."); -} diff --git a/host/lib/usrp_clock/octoclock/ihexcvt.hpp b/host/lib/usrp_clock/octoclock/ihexcvt.hpp deleted file mode 100644 index d577ece1f..000000000 --- a/host/lib/usrp_clock/octoclock/ihexcvt.hpp +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// -// 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 3 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, see <http://www.gnu.org/licenses/>. -// -#ifndef _IHEXCVT_HPP_ -#define _IHEXCVT_HPP_ - -void Hex2Bin(const char* SrcName, const char* DstName, bool IgnoreChecksum); - -#endif /* _IHEXCVT_HPP_ */ diff --git a/host/lib/usrp_clock/octoclock/kk_ihex.h b/host/lib/usrp_clock/octoclock/kk_ihex.h new file mode 100644 index 000000000..20eba43cc --- /dev/null +++ b/host/lib/usrp_clock/octoclock/kk_ihex.h @@ -0,0 +1,191 @@ +/* + * kk_ihex.h: A simple library for reading and writing the Intel HEX  + * or IHEX format. Intended mainly for embedded systems, and thus + * somewhat optimised for size at the expense of error handling and + * generality. + * + *      USAGE + *      ----- + * + * The library has been split into read and write parts, which use a + * common data structure (`struct ihex_state`), but each can be used + * independently. Include the header `kk_ihex_read.h` for reading, and/or + * the header `kk_ihex_write.h` for writing (and link with their respective + * object files). Both can be used simultaneously - this header defines + * the shared data structures and definitions. + * + * + *      READING INTEL HEX DATA + *      ---------------------- + * + * To read data in the Intel HEX format, you must perform the actual reading + * of bytes using other means (e.g., stdio). The bytes read must then be + * passed to `ihex_read_byte` and/or `ihex_read_bytes`. The reading functions + * will then call `ihex_data_read`, at which stage the `struct ihex_state` + * structure will contain the data along with its address. See the header + * `kk_ihex_read.h` for details and example implementation of `ihex_data_read`. + * + * The sequence to read data in IHEX format is: + *      struct ihex_state ihex; + *      ihex_begin_read(&ihex); + *      ihex_read_bytes(&ihex, my_input_bytes, length_of_my_input_bytes); + *      ihex_end_read(&ihex); + * + * + *      WRITING BINARY DATA AS INTEL HEX + *      -------------------------------- + * + * In order to write out data, the `ihex_write_at_address` or + * `ihex_write_at_segment` functions are used to set the data location, + * and then the binary bytes are written with `ihex_write_byte` and/or + * `ihex_write_bytes`. The writing functions will then call the function + * `ihex_flush_buffer` whenever the internal write buffer needs to be + * cleared - it is up to the caller to provide an implementation of + * `ihex_flush_buffer` to do the actual writing. See the header + * `kk_ihex_write.h` for details and an example implementation. + * + * See the declaration further down for an example implementation. + * + * The sequence to write data in IHEX format is: + *      struct ihex_state ihex; + *      ihex_init(&ihex); + *      ihex_write_at_address(&ihex, 0); + *      ihex_write_bytes(&ihex, my_data, length_of_my_data); + *      ihex_end_write(&ihex); + * + * For outputs larger than 64KiB, 32-bit linear addresses are output. Normally + * the initial linear extended address record of zero is NOT written - it can + * be forced by setting `ihex->flags |= IHEX_FLAG_ADDRESS_OVERFLOW` before + * writing the first byte. + * + * Gaps in the data may be created by calling `ihex_write_at_address` with the + * new starting address without calling `ihex_end_write` in between. + * + * + * The same `struct ihex_state` may be used either for reading or writing, + * but NOT both at the same time. Furthermore, a global output buffer is + * used for writing, i.e., multiple threads must not write simultaneously + * (but multiple writes may be interleaved). + * + * + *      CONSERVING MEMORY + *      ----------------- + * + * For memory-critical use, you can save additional memory by defining + * `IHEX_LINE_MAX_LENGTH` as something less than 255. Note, however, that + * this limit affects both reading and writing, so the resulting library + * will be unable to read lines with more than this number of data bytes. + * That said, I haven't encountered any IHEX files with more than 32 + * data bytes per line. For write only there is no reason to define the + * maximum as greater than the line length you'll actually be writing, + * e.g., 32 or 16. + * + * If the write functionality is only occasionally used, you can provide + * your own buffer for the duration by defining `IHEX_EXTERNAL_WRITE_BUFFER` + * and providing a `char *ihex_write_buffer` which points to valid storage + * for at least `IHEX_WRITE_BUFFER_LENGTH` characters from before the first + * call to any IHEX write function to until after the last. + * + * If you are doing both reading and writing, you can define the maximum + * output length separately as `IHEX_MAX_OUTPUT_LINE_LENGTH` - this will + * decrease the write buffer size, but `struct ihex_state` will still + * use the larger `IHEX_LINE_MAX_LENGTH` for its data storage. + * + * You can also save a few additional bytes by disabling support for + * segmented addresses, by defining `IHEX_DISABLE_SEGMENTS`. Both the + * read and write modules need to be build with the same option, as the + * resulting data structures will not be compatible otherwise. To be honest, + * this is a fairly pointless optimisation. + * + * + * Copyright (c) 2013-2015 Kimmo Kulovesi, http://arkku.com/ + * Provided with absolutely no warranty, use at your own risk only. + * Use and distribute freely, mark modified copies as such. + */ + +#ifndef KK_IHEX_H +#define KK_IHEX_H + +#define KK_IHEX_VERSION "2015-08-10" + +#include <stdint.h> + +#ifdef IHEX_USE_STDBOOL +#include <stdbool.h> +typedef bool ihex_bool_t; +#else +typedef uint_fast8_t ihex_bool_t; +#endif + +typedef uint_least32_t ihex_address_t; +typedef uint_least16_t ihex_segment_t; +typedef int ihex_count_t; + +// Maximum number of data bytes per line (applies to both reading and +// writing!); specify 255 to support reading all possible lengths. Less +// can be used to limit memory footprint on embedded systems, e.g., +// most programs with IHEX output use 32. +#ifndef IHEX_LINE_MAX_LENGTH +#define IHEX_LINE_MAX_LENGTH 255 +#endif + +enum ihex_flags { +    IHEX_FLAG_ADDRESS_OVERFLOW = 0x80   // 16-bit address overflow +}; +typedef uint8_t ihex_flags_t; + +typedef struct ihex_state { +    ihex_address_t  address; +#ifndef IHEX_DISABLE_SEGMENTS +    ihex_segment_t  segment; +#endif +    ihex_flags_t    flags; +    uint8_t         line_length; +    uint8_t         length; +    uint8_t         data[IHEX_LINE_MAX_LENGTH + 1]; +} kk_ihex_t; + +enum ihex_record_type { +    IHEX_DATA_RECORD, +    IHEX_END_OF_FILE_RECORD, +    IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD, +    IHEX_START_SEGMENT_ADDRESS_RECORD, +    IHEX_EXTENDED_LINEAR_ADDRESS_RECORD, +    IHEX_START_LINEAR_ADDRESS_RECORD +}; +typedef uint8_t ihex_record_type_t; + +#ifndef IHEX_DISABLE_SEGMENTS + +// Resolve segmented address (if any). It is the author's recommendation that +// segmented addressing not be used (and indeed the write function of this +// library uses linear 32-bit addressing unless manually overridden). +// +#define IHEX_LINEAR_ADDRESS(ihex) ((ihex)->address + (((ihex_address_t)((ihex)->segment)) << 4)) +// +// Note that segmented addressing with the above macro is not strictly adherent +// to the IHEX specification, which mandates that the lowest 16 bits of the +// address and the index of the data byte must be added modulo 64K (i.e., +// at 16 bits precision with wraparound) and the segment address only added +// afterwards. +// +// To implement fully correct segmented addressing, compute the address +// of _each byte_ with its index in `data` as follows: +// +#define IHEX_BYTE_ADDRESS(ihex, byte_index) ((((ihex)->address + (byte_index)) & 0xFFFFU) + (((ihex_address_t)((ihex)->segment)) << 4)) + +#else // IHEX_DISABLE_SEGMENTS: + +#define IHEX_LINEAR_ADDRESS(ihex) ((ihex)->address) +#define IHEX_BYTE_ADDRESS(ihex, byte_index) ((ihex)->address + (byte_index)) + +#endif + +// The newline string (appended to every output line, e.g., "\r\n") +#ifndef IHEX_NEWLINE_STRING +#define IHEX_NEWLINE_STRING "\n" +#endif + +// See kk_ihex_read.h and kk_ihex_write.h for function declarations! + +#endif // !KK_IHEX_H diff --git a/host/lib/usrp_clock/octoclock/kk_ihex_license.txt b/host/lib/usrp_clock/octoclock/kk_ihex_license.txt new file mode 100644 index 000000000..530f413e3 --- /dev/null +++ b/host/lib/usrp_clock/octoclock/kk_ihex_license.txt @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-2015 Kimmo Kulovesi + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/host/lib/usrp_clock/octoclock/kk_ihex_read.c b/host/lib/usrp_clock/octoclock/kk_ihex_read.c new file mode 100644 index 000000000..964cdd165 --- /dev/null +++ b/host/lib/usrp_clock/octoclock/kk_ihex_read.c @@ -0,0 +1,261 @@ +/* + * kk_ihex_read.c: A simple library for reading the Intel HEX (IHEX) format. + * + * See the header `kk_ihex.h` for instructions. + * + * Copyright (c) 2013-2015 Kimmo Kulovesi, http://arkku.com/ + * Provided with absolutely no warranty, use at your own risk only. + * Use and distribute freely, mark modified copies as such. + * + * Modifications Copyright (c) 2015 National Instruments Corp. + */ + +#include "kk_ihex_read.h" + +#include <stdio.h> +#include <stdlib.h> + +#define IHEX_START ':' + +#define AUTODETECT_ADDRESS (~0UL) + +#define ADDRESS_HIGH_MASK ((ihex_address_t) 0xFFFF0000U) + +enum ihex_read_state { +    READ_WAIT_FOR_START = 0, +    READ_COUNT_HIGH = 1, +    READ_COUNT_LOW, +    READ_ADDRESS_MSB_HIGH, +    READ_ADDRESS_MSB_LOW, +    READ_ADDRESS_LSB_HIGH, +    READ_ADDRESS_LSB_LOW, +    READ_RECORD_TYPE_HIGH, +    READ_RECORD_TYPE_LOW, +    READ_DATA_HIGH, +    READ_DATA_LOW +}; + +#define IHEX_READ_RECORD_TYPE_MASK 0x07 +#define IHEX_READ_STATE_MASK 0x78 +#define IHEX_READ_STATE_OFFSET 3 + +void +ihex_begin_read (struct ihex_state * const ihex) { +    ihex->address = 0; +#ifndef IHEX_DISABLE_SEGMENTS +    ihex->segment = 0; +#endif +    ihex->flags = 0; +    ihex->line_length = 0; +    ihex->length = 0; +} + +void +ihex_read_at_address (struct ihex_state * const ihex, ihex_address_t address) { +    ihex_begin_read(ihex); +    ihex->address = address; +} + +#ifndef IHEX_DISABLE_SEGMENTS +void +ihex_read_at_segment (struct ihex_state * const ihex, ihex_segment_t segment) { +    ihex_begin_read(ihex); +    ihex->segment = segment; +} +#endif + +void +ihex_end_read (struct ihex_state * const ihex, FILE* outfile) { +    uint_fast8_t type = ihex->flags & IHEX_READ_RECORD_TYPE_MASK; +    uint_fast8_t sum; +    if ((sum = ihex->length) == 0 && type == IHEX_DATA_RECORD) { +        return; +    } +    { +        // compute and validate checksum +        const uint8_t * const eptr = ihex->data + sum; +        const uint8_t *r = ihex->data; +        sum += type + (ihex->address & 0xFFU) + ((ihex->address >> 8) & 0xFFU); +        while (r != eptr) { +            sum += *r++; +        } +        sum = (~sum + 1U) ^ *eptr; // *eptr is the received checksum +    } +    if (ihex_data_read(ihex, type, sum, outfile)) { +        if (type == IHEX_EXTENDED_LINEAR_ADDRESS_RECORD) { +            ihex->address &= 0xFFFFU; +            ihex->address |= (((ihex_address_t) ihex->data[0]) << 24) | +                             (((ihex_address_t) ihex->data[1]) << 16); +#ifndef IHEX_DISABLE_SEGMENTS +        } else if (type == IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD) { +            ihex->segment = (ihex_segment_t) ((ihex->data[0] << 8) | ihex->data[1]); +#endif +        } +    } +    ihex->length = 0; +    ihex->flags = 0; +} + +void +ihex_read_byte (struct ihex_state * const ihex, const char byte, FILE* outfile) { +    uint_fast8_t b = (uint_fast8_t) byte; +    uint_fast8_t len = ihex->length; +    uint_fast8_t state = (ihex->flags & IHEX_READ_STATE_MASK); +    ihex->flags ^= state; // turn off the old state +    state >>= IHEX_READ_STATE_OFFSET; + +    if (b >= '0' && b <= '9') { +        b -= '0'; +    } else if (b >= 'A' && b <= 'F') { +        b -= 'A' - 10; +    } else if (b >= 'a' && b <= 'f') { +        b -= 'a' - 10; +    } else if (b == IHEX_START) { +        // sync to a new record at any state +        state = READ_COUNT_HIGH; +        goto end_read; +    } else { +        // ignore unknown characters (e.g., extra whitespace) +        goto save_read_state; +    } + +    if (!(++state & 1)) { +        // high nybble, store temporarily at end of data: +        b <<= 4; +        ihex->data[len] = b; +    } else { +        // low nybble, combine with stored high nybble: +        b = (ihex->data[len] |= b); +        switch (state >> 1) { +        default: +            // remain in initial state while waiting for : +            return; +        case (READ_COUNT_LOW >> 1): +            // data length +            ihex->line_length = b; +#if IHEX_LINE_MAX_LENGTH < 255 +            if (b > IHEX_LINE_MAX_LENGTH) { +                ihex_end_read(ihex); +                return; +            } +#endif +            break; +        case (READ_ADDRESS_MSB_LOW >> 1): +            // high byte of 16-bit address +            ihex->address &= ADDRESS_HIGH_MASK; // clear the 16-bit address +            ihex->address |= ((ihex_address_t) b) << 8U; +            break; +        case (READ_ADDRESS_LSB_LOW >> 1): +            // low byte of 16-bit address +            ihex->address |= (ihex_address_t) b; +            break; +        case (READ_RECORD_TYPE_LOW >> 1): +            // record type +            if (b & ~IHEX_READ_RECORD_TYPE_MASK) { +                // skip unknown record types silently +                return; +            }  +            ihex->flags = (ihex->flags & ~IHEX_READ_RECORD_TYPE_MASK) | b; +            break; +        case (READ_DATA_LOW >> 1): +            if (len < ihex->line_length) { +                // data byte +                ihex->length = len + 1; +                state = READ_DATA_HIGH; +                goto save_read_state; +            } +            // end of line (last "data" byte is checksum) +            state = READ_WAIT_FOR_START; +        end_read: +            ihex_end_read(ihex, outfile); +        } +    } +save_read_state: +    ihex->flags |= state << IHEX_READ_STATE_OFFSET; +} + +void +ihex_read_bytes (struct ihex_state * ihex, +                 const char * data, +                 ihex_count_t count, +		 FILE* outfile) { +    while (count > 0) { +        ihex_read_byte(ihex, *data++, outfile); +        --count; +    } +} + +ihex_bool_t +ihex_data_read (struct ihex_state *ihex, +                ihex_record_type_t type, +                ihex_bool_t error, +		FILE* outfile) { +    unsigned long line_number = 1L; +    unsigned long file_position = 0L; +    unsigned long address_offset = 0L; +    bool debug_enabled = false; + +    if (error) { +        (void) fprintf(stderr, "Checksum error on line %lu\n", line_number); +        return false; +    } +    if ((error = (ihex->length < ihex->line_length))) { +        (void) fprintf(stderr, "Line length error on line %lu\n", line_number); +        return false; +    } +    if (!outfile) { +        (void) fprintf(stderr, "Excess data after end of file record\n"); +        return false; +    } +    if (type == IHEX_DATA_RECORD) { +        unsigned long address = (unsigned long) IHEX_LINEAR_ADDRESS(ihex); +        if (address < address_offset) { +            if (address_offset == AUTODETECT_ADDRESS) { +                // autodetect initial address +                address_offset = address; +                if (debug_enabled) { +                    (void) fprintf(stderr, "Address offset: 0x%lx\n", +                            address_offset); +                } +            } else { +                (void) fprintf(stderr, "Address underflow on line %lu\n", +                        line_number); +                return false; +            } +        } +        address -= address_offset; +        if (address != file_position) { +            if (debug_enabled) { +                (void) fprintf(stderr, +                        "Seeking from 0x%lx to 0x%lx on line %lu\n", +                        file_position, address, line_number); +            } +            if (outfile == stdout || fseek(outfile, (long) address, SEEK_SET)) { +                if (file_position < address) { +                    // "seek" forward in stdout by writing NUL bytes +                    do { +                        (void) fputc('\0', outfile); +                    } while (++file_position < address); +                } else { +                    perror("fseek"); +                    return false; +                } +            } +            file_position = address; +        } +        if (!fwrite(ihex->data, ihex->length, 1, outfile)) { +            perror("fwrite"); +            return false; +        } +        file_position += ihex->length; +    } else if (type == IHEX_END_OF_FILE_RECORD) { +        if (debug_enabled) { +            (void) fprintf(stderr, "%lu bytes written\n", file_position); +        } +        if (outfile != stdout) { +            (void) fclose(outfile); +        } +        outfile = NULL; +    } +    return true; +} diff --git a/host/lib/usrp_clock/octoclock/kk_ihex_read.h b/host/lib/usrp_clock/octoclock/kk_ihex_read.h new file mode 100644 index 000000000..5e210fddb --- /dev/null +++ b/host/lib/usrp_clock/octoclock/kk_ihex_read.h @@ -0,0 +1,119 @@ +/* + * kk_ihex_read.h: A simple library for reading Intel HEX data. See + * the accompanying kk_ihex_write.h for IHEX write support. + * + * + *      READING INTEL HEX DATA + *      ---------------------- + * + * To read data in the Intel HEX format, you must perform the actual reading + * of bytes using other means (e.g., stdio). The bytes read must then be + * passed to `ihex_read_byte` and/or `ihex_read_bytes`. The reading functions + * will then call `ihex_data_read`, at which stage the `struct ihex_state` + * structure will contain the data along with its address. See below for + * details and example implementation of `ihex_data_read`. + * + * The sequence to read data in IHEX format is: + *      struct ihex_state ihex; + *      ihex_begin_read(&ihex); + *      ihex_read_bytes(&ihex, my_input_bytes, length_of_my_input_bytes); + *      ihex_end_read(&ihex); + * + * + *      CONSERVING MEMORY + *      ----------------- + * + * For memory-critical use, you can save additional memory by defining + * `IHEX_LINE_MAX_LENGTH` as something less than 255. Note, however, that + * this limit affects both reading and writing, so the resulting library + * will be unable to read lines with more than this number of data bytes. + * That said, I haven't encountered any IHEX files with more than 32 + * data bytes per line. + * + * + * Copyright (c) 2013-2015 Kimmo Kulovesi, http://arkku.com/ + * Provided with absolutely no warranty, use at your own risk only. + * Use and distribute freely, mark modified copies as such. + * + * Modifications Copyright (c) 2015 National Instruments Corp. + */ + +#ifndef KK_IHEX_READ_H +#define KK_IHEX_READ_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "kk_ihex.h" + +#include <stdio.h> + +// Begin reading at address 0 +void ihex_begin_read(struct ihex_state * const ihex); + +// Begin reading at `address` (the lowest 16 bits of which will be ignored); +// this is required only if the high bytes of the 32-bit starting address +// are not specified in the input data and they are non-zero +void ihex_read_at_address(struct ihex_state *ihex, +                          ihex_address_t address); + +// Read a single character +void ihex_read_byte(struct ihex_state *ihex, char chr, FILE* outfile); + +// Read `count` bytes from `data` +void ihex_read_bytes(struct ihex_state * ihex, +                     const char * data, +                     ihex_count_t count, +                     FILE* outfile); + +// End reading (may call `ihex_data_read` if there is data waiting) +void ihex_end_read(struct ihex_state *ihex, FILE* outfile); + +// Called when a complete line has been read, the record type of which is +// passed as `type`. The `ihex` structure will have its fields `data`, +// `line_length`, `address`, and `segment` set appropriately. In case +// of reading an `IHEX_EXTENDED_LINEAR_ADDRESS_RECORD` or an +// `IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD` the record's data is not +// yet parsed - it will be parsed into the `address` or `segment` field +// only if `ihex_data_read` returns `true`. This allows manual handling +// of extended addresses by parsing the `ihex->data` bytes. +// +// Possible error cases include checksum mismatch (which is indicated +// as an argument), and excessive line length (in case this has been +// compiled with `IHEX_LINE_MAX_LENGTH` less than 255) which is indicated +// by `line_length` greater than `length`. Unknown record types and +// other erroneous data is usually silently ignored by this minimalistic +// parser. (It is recommended to compute a hash over the complete data +// once received and verify that against the source.) +// +// Example implementation: +// +//      ihex_bool_t ihex_data_read(struct ihex_state *ihex, +//                                 ihex_record_type_t type, +//                                 ihex_bool_t error) { +//          error = error || (ihex->length < ihex->line_length); +//          if (type == IHEX_DATA_RECORD && !error) { +//              (void) fseek(outfile, IHEX_LINEAR_ADDRESS(ihex), SEEK_SET); +//              (void) fwrite(ihex->data, 1, ihex->length, outfile); +//          } else if (type == IHEX_END_OF_FILE_RECORD) { +//              (void) fclose(outfile); +//          } +//          return !error; +//      } +// +ihex_bool_t ihex_data_read(struct ihex_state *ihex, +                           ihex_record_type_t type, +                           ihex_bool_t checksum_mismatch, +                           FILE* outfile); + +// Begin reading at `segment`; this is required only if the initial segment +// is not specified in the input data and it is non-zero. +// +#ifndef IHEX_DISABLE_SEGMENTS +void ihex_read_at_segment(struct ihex_state *ihex, ihex_segment_t segment); +#endif + +#ifdef __cplusplus +} +#endif +#endif // !KK_IHEX_READ_H diff --git a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp index e8c50e029..8b47da7e5 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp @@ -15,16 +15,9 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <cstring> -#include <fstream> -#include <iostream> -#include <string> - -#include <boost/cstdint.hpp> -#include <boost/filesystem.hpp> -#include <boost/format.hpp> -#include <boost/lexical_cast.hpp> -#include <boost/thread.hpp> +#include "octoclock_impl.hpp" +#include "common.h" +#include "kk_ihex_read.h"  #include <uhd/device.hpp>  #include <uhd/image_loader.hpp> @@ -35,9 +28,17 @@  #include <uhd/utils/paths.hpp>  #include <uhd/utils/static.hpp> -#include "octoclock_impl.hpp" -#include "common.h" -#include "ihexcvt.hpp" +#include <boost/cstdint.hpp> +#include <boost/filesystem.hpp> +#include <boost/format.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/thread.hpp> + +#include <cstdio> +#include <cstring> +#include <fstream> +#include <iostream> +#include <string>  namespace fs = boost::filesystem;  using namespace uhd; @@ -74,13 +75,32 @@ static void octoclock_calculate_crc(octoclock_session_t &session){          session.crc ^= temp_image[i];          for(boost::uint8_t j = 0; j < 8; ++j){              if(session.crc & 1) session.crc = (session.crc >> 1) ^ 0xA001; -            else session.crc = (session.crc >> 1);  -        }    -    }    +            else session.crc = (session.crc >> 1); +        } +    }      ifile.close();  } +static void octoclock_convert_ihex(octoclock_session_t &session){ +    struct ihex_state ihex; +    ihex_count_t count; +    char buf[256]; +    FILE* infile = fopen(session.given_filepath.c_str(), "r"); +    FILE* outfile = fopen(session.actual_filepath.c_str(), "w"); +    uint64_t line_number = 1; + +    ihex_begin_read(&ihex); +    while(fgets(buf, 256, infile)){ +        count = ihex_count_t(strlen(buf)); +        ihex_read_bytes(&ihex, buf, count, outfile); +        line_number += (count && buf[count - 1] == '\n'); +    } +    ihex_end_read(&ihex, outfile); // Closes outfile + +    (void)fclose(infile); +} +  static void octoclock_validate_firmware_image(octoclock_session_t &session){      if(not fs::exists(session.given_filepath)){          throw uhd::runtime_error(str(boost::format("Could not find image at path \"%s\"") @@ -98,7 +118,7 @@ static void octoclock_validate_firmware_image(octoclock_session_t &session){                                                 % time_spec_t::get_system_time().get_full_secs())                                            ).string(); -        Hex2Bin(session.given_filepath.c_str(), session.actual_filepath.c_str(), false); +        octoclock_convert_ihex(session);          session.from_hex = true;      }      else throw uhd::runtime_error(str(boost::format("Invalid extension \"%s\". Extension must be .hex or .bin."))); diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 06bee48cd..4f56dad0d 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -84,9 +84,11 @@ IF(ENABLE_OCTOCLOCK)      SET(octoclock_burner_sources          octoclock_firmware_burner.cpp -        ihexcvt.cpp +        ${CMAKE_SOURCE_DIR}/lib/usrp_clock/octoclock/kk_ihex_read.c      ) +    ADD_DEFINITIONS(-DIHEX_USE_STDBOOL) +    INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp_clock/octoclock)      ADD_EXECUTABLE(octoclock_firmware_burner ${octoclock_burner_sources})      TARGET_LINK_LIBRARIES(octoclock_firmware_burner uhd ${Boost_LIBRARIES})      UHD_INSTALL(TARGETS octoclock_firmware_burner RUNTIME DESTINATION ${RUNTIME_DIR} COMPONENT utilities) diff --git a/host/utils/ihexcvt.cpp b/host/utils/ihexcvt.cpp deleted file mode 100644 index 0605ee61c..000000000 --- a/host/utils/ihexcvt.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/*  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."); -} diff --git a/host/utils/ihexcvt.hpp b/host/utils/ihexcvt.hpp deleted file mode 100644 index d577ece1f..000000000 --- a/host/utils/ihexcvt.hpp +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// -// 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 3 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, see <http://www.gnu.org/licenses/>. -// -#ifndef _IHEXCVT_HPP_ -#define _IHEXCVT_HPP_ - -void Hex2Bin(const char* SrcName, const char* DstName, bool IgnoreChecksum); - -#endif /* _IHEXCVT_HPP_ */ diff --git a/host/utils/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp index 1ec77d0c8..272394860 100644 --- a/host/utils/octoclock_firmware_burner.cpp +++ b/host/utils/octoclock_firmware_burner.cpp @@ -42,7 +42,7 @@  #include <uhd/utils/safe_main.hpp>  #include "../lib/usrp_clock/octoclock/common.h" -#include "ihexcvt.hpp" +#include "kk_ihex_read.h"  #define MAX_FIRMWARE_SIZE 1024*120  #define BLOCK_SIZE 256 @@ -291,6 +291,25 @@ void finalize(udp_simple::sptr udp_transport){      }  } +void octoclock_convert_ihex(const std::string &hex_path, const std::string &bin_path){ +    struct ihex_state ihex; +    ihex_count_t count; +    char buf[256]; +    FILE* infile = fopen(hex_path.c_str(), "r"); +    FILE* outfile = fopen(bin_path.c_str(), "w"); +    uint64_t line_number = 1; + +    ihex_begin_read(&ihex); +    while(fgets(buf, 256, infile)){ +        count = ihex_count_t(strlen(buf)); +        ihex_read_bytes(&ihex, buf, count, outfile); +        line_number += (count && buf[count - 1] == '\n'); +    } +    ihex_end_read(&ihex, outfile); // Closes outfile + +    (void)fclose(infile); +} +  int UHD_SAFE_MAIN(UHD_UNUSED(int argc), UHD_UNUSED(char *argv[])){      std::string ip_addr; @@ -352,7 +371,7 @@ int UHD_SAFE_MAIN(UHD_UNUSED(int argc), UHD_UNUSED(char *argv[])){          //Write firmware .bin file to temporary directory          fs::path temp_bin = fs::path(fs::path(get_tmp_path()) / str(boost::format("octoclock_fw_%d.bin")                                                            % time_spec_t::get_system_time().get_full_secs())); -        Hex2Bin(firmware_path.c_str(), temp_bin.string().c_str(), false); +        octoclock_convert_ihex(firmware_path, temp_bin.string());          actual_firmware_path = temp_bin.string();      } | 
