diff options
-rw-r--r-- | host/lib/usrp_clock/octoclock/CMakeLists.txt | 3 | ||||
-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 | 119 | ||||
-rw-r--r-- | host/utils/CMakeLists.txt | 2 | ||||
-rw-r--r-- | host/utils/octoclock_firmware_burner.cpp | 22 |
8 files changed, 49 insertions, 688 deletions
diff --git a/host/lib/usrp_clock/octoclock/CMakeLists.txt b/host/lib/usrp_clock/octoclock/CMakeLists.txt index a74cb034f..a54d27c52 100644 --- a/host/lib/usrp_clock/octoclock/CMakeLists.txt +++ b/host/lib/usrp_clock/octoclock/CMakeLists.txt @@ -21,10 +21,7 @@ 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}/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/kk_ihex.h b/host/lib/usrp_clock/octoclock/kk_ihex.h deleted file mode 100644 index 20eba43cc..000000000 --- a/host/lib/usrp_clock/octoclock/kk_ihex.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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 deleted file mode 100644 index 530f413e3..000000000 --- a/host/lib/usrp_clock/octoclock/kk_ihex_license.txt +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 964cdd165..000000000 --- a/host/lib/usrp_clock/octoclock/kk_ihex_read.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * 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 deleted file mode 100644 index 303622b18..000000000 --- a/host/lib/usrp_clock/octoclock/kk_ihex_read.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 * const ihex, - ihex_address_t address); - -// Read a single character -void ihex_read_byte(struct ihex_state * const ihex, const char byte, 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 * const 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 8b47da7e5..1d4699f54 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp @@ -17,8 +17,8 @@ #include "octoclock_impl.hpp" #include "common.h" -#include "kk_ihex_read.h" +#include "../../utils/ihex.hpp" #include <uhd/device.hpp> #include <uhd/image_loader.hpp> #include <uhd/transport/udp_simple.hpp> @@ -34,6 +34,8 @@ #include <boost/lexical_cast.hpp> #include <boost/thread.hpp> +#include <algorithm> +#include <iterator> #include <cstdio> #include <cstring> #include <fstream> @@ -54,83 +56,71 @@ using namespace uhd::transport; typedef struct { bool found; uhd::device_addr_t dev_addr; - std::string given_filepath; - std::string actual_filepath; // If using a .hex, this is the converted .bin - bool from_hex; - boost::uint32_t size; + std::string image_filepath; boost::uint16_t crc; boost::uint16_t num_blocks; udp_simple::sptr ctrl_xport; udp_simple::sptr fw_xport; boost::uint8_t data_in[udp_simple::mtu]; + std::vector<boost::uint8_t> image; } octoclock_session_t; static void octoclock_calculate_crc(octoclock_session_t &session){ - std::ifstream ifile(session.actual_filepath.c_str()); - boost::uint8_t temp_image[OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES]; - ifile.read((char*)temp_image, session.size); - session.crc = 0xFFFF; - for(size_t i = 0; i < session.size; i++){ - session.crc ^= temp_image[i]; + for(size_t i = 0; i < session.image.size(); i++) + { + session.crc ^= session.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); } } - - 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'); +static void octoclock_read_bin(octoclock_session_t &session) +{ + std::ifstream bin_file(session.image_filepath.c_str()); + if (not bin_file.is_open()) { + throw uhd::io_error("Could not read image file."); } - ihex_end_read(&ihex, outfile); // Closes outfile - (void)fclose(infile); + size_t filesize = fs::file_size(session.image_filepath); + session.image.clear(); + session.image.reserve(filesize); + + std::copy( + std::istream_iterator<boost::uint8_t>(bin_file), + std::istream_iterator<boost::uint8_t>(), + std::back_inserter(session.image) + ); + + bin_file.close(); } static void octoclock_validate_firmware_image(octoclock_session_t &session){ - if(not fs::exists(session.given_filepath)){ + if(not fs::exists(session.image_filepath)){ throw uhd::runtime_error(str(boost::format("Could not find image at path \"%s\"") - % session.given_filepath)); + % session.image_filepath)); } - std::string extension = fs::extension(session.given_filepath); + std::string extension = fs::extension(session.image_filepath); if(extension == ".bin"){ - session.actual_filepath = session.given_filepath; - session.from_hex = false; + octoclock_read_bin(session); } else if(extension == ".hex"){ - session.actual_filepath = fs::path(fs::path(uhd::get_tmp_path()) / - str(boost::format("octoclock_fw_%d.bin") - % time_spec_t::get_system_time().get_full_secs()) - ).string(); - - octoclock_convert_ihex(session); - session.from_hex = true; + ihex_reader hex_reader(session.image_filepath); + session.image = hex_reader.to_vector(OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES); } else throw uhd::runtime_error(str(boost::format("Invalid extension \"%s\". Extension must be .hex or .bin."))); - session.size = fs::file_size(session.actual_filepath); - if(session.size > OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES){ + if(session.image.size() > OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES){ throw uhd::runtime_error(str(boost::format("The specified firmware image is too large: %d vs. %d") - % session.size % OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES)); + % session.image.size() % OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES)); } - session.num_blocks = (session.size % OCTOCLOCK_BLOCK_SIZE) ? ((session.size / OCTOCLOCK_BLOCK_SIZE) + 1) - : (session.size / OCTOCLOCK_BLOCK_SIZE); + session.num_blocks = (session.image.size() % OCTOCLOCK_BLOCK_SIZE) + ? ((session.image.size() / OCTOCLOCK_BLOCK_SIZE) + 1) + : (session.image.size() / OCTOCLOCK_BLOCK_SIZE); octoclock_calculate_crc(session); } @@ -164,14 +154,15 @@ static void octoclock_setup_session(octoclock_session_t &session, } session.dev_addr = devs[0]; + session.found = true; // If no filepath is given, use the default if(filepath == ""){ - session.given_filepath = find_image_path(str(boost::format("octoclock_r%s_fw.hex") + session.image_filepath = find_image_path(str(boost::format("octoclock_r%s_fw.hex") % session.dev_addr.get("revision","4") )); } - else session.given_filepath = filepath; + else session.image_filepath = filepath; octoclock_validate_firmware_image(session); @@ -231,10 +222,10 @@ static void octoclock_burn(octoclock_session_t &session){ const octoclock_packet_t* pkt_in = reinterpret_cast<const octoclock_packet_t*>(session.data_in); // Tell OctoClock to prepare for burn - pkt_out.len = htonx<boost::uint16_t>(session.size); + pkt_out.len = htonx<boost::uint16_t>(session.image.size()); size_t len = 0; std::cout << " -- Preparing OctoClock for firmware load..." << std::flush; - pkt_out.len = session.size; + pkt_out.len = session.image.size(); pkt_out.crc = session.crc; UHD_OCTOCLOCK_SEND_AND_RECV(session.fw_xport, PREPARE_FW_BURN_CMD, pkt_out, len, session.data_in); if(UHD_OCTOCLOCK_PACKET_MATCHES(FW_BURN_READY_ACK, pkt_out, pkt_in, len)){ @@ -242,14 +233,10 @@ static void octoclock_burn(octoclock_session_t &session){ } else{ std::cout << "failed." << std::endl; - if(session.from_hex){ - fs::remove(session.actual_filepath); - } throw uhd::runtime_error("Failed to prepare OctoClock for firmware load."); } // Start burning - std::ifstream image(session.actual_filepath.c_str(), std::ios::binary); for(size_t i = 0; i < session.num_blocks; i++){ pkt_out.sequence++; pkt_out.addr = i * OCTOCLOCK_BLOCK_SIZE; @@ -260,14 +247,10 @@ static void octoclock_burn(octoclock_session_t &session){ << std::flush; memset(pkt_out.data, 0, OCTOCLOCK_BLOCK_SIZE); - image.read((char*)pkt_out.data, OCTOCLOCK_BLOCK_SIZE); + memcpy((char*)pkt_out.data, &session.image[pkt_out.addr], OCTOCLOCK_BLOCK_SIZE); UHD_OCTOCLOCK_SEND_AND_RECV(session.fw_xport, FILE_TRANSFER_CMD, pkt_out, len, session.data_in); if(not UHD_OCTOCLOCK_PACKET_MATCHES(FILE_TRANSFER_ACK, pkt_out, pkt_in, len)){ - image.close(); std::cout << std::endl; - if(session.from_hex){ - fs::remove(session.actual_filepath); - } throw uhd::runtime_error("Failed to load firmware."); } } @@ -275,7 +258,6 @@ static void octoclock_burn(octoclock_session_t &session){ std::cout << str(boost::format("\r -- Loading firmware: 100%% (%d/%d blocks)") % session.num_blocks % session.num_blocks) << std::endl; - image.close(); } static void octoclock_verify(octoclock_session_t &session){ @@ -285,7 +267,6 @@ static void octoclock_verify(octoclock_session_t &session){ const octoclock_packet_t* pkt_in = reinterpret_cast<const octoclock_packet_t*>(session.data_in); size_t len = 0; - std::ifstream image(session.actual_filepath.c_str(), std::ios::binary); boost::uint8_t image_part[OCTOCLOCK_BLOCK_SIZE]; boost::uint16_t cmp_len = 0; for(size_t i = 0; i < session.num_blocks; i++){ @@ -298,34 +279,22 @@ static void octoclock_verify(octoclock_session_t &session){ << std::flush; memset(image_part, 0, OCTOCLOCK_BLOCK_SIZE); - image.read((char*)image_part, OCTOCLOCK_BLOCK_SIZE); - cmp_len = image.gcount(); + memcpy((char*)image_part, &session.image[pkt_out.addr], OCTOCLOCK_BLOCK_SIZE); + cmp_len = std::min<size_t>(OCTOCLOCK_BLOCK_SIZE, session.image.size() - size_t(pkt_out.addr)); UHD_OCTOCLOCK_SEND_AND_RECV(session.fw_xport, READ_FW_CMD, pkt_out, len, session.data_in); if(UHD_OCTOCLOCK_PACKET_MATCHES(READ_FW_ACK, pkt_out, pkt_in, len)){ if(memcmp(pkt_in->data, image_part, cmp_len)){ std::cout << std::endl; - image.close(); - if(session.from_hex){ - fs::remove(session.actual_filepath); - } throw uhd::runtime_error("Failed to verify OctoClock firmware."); } } else{ std::cout << std::endl; - image.close(); - if(session.from_hex){ - fs::remove(session.actual_filepath); - } throw uhd::runtime_error("Failed to verify OctoClock firmware."); } } - image.close(); - if(session.from_hex){ - fs::remove(session.actual_filepath); - } std::cout << str(boost::format("\r -- Verifying firmware load: 100%% (%d/%d blocks)") % session.num_blocks % session.num_blocks) << std::endl; @@ -360,7 +329,7 @@ bool octoclock_image_loader(const image_loader::image_loader_args_t &image_loade std::cout << boost::format("Unit: OctoClock (%s)") % session.dev_addr["addr"] << std::endl; - std::cout << "Firmware: " << session.given_filepath << std::endl; + std::cout << "Firmware: " << session.image_filepath << std::endl; octoclock_burn(session); octoclock_verify(session); diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 4f56dad0d..8367c0184 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -84,7 +84,7 @@ IF(ENABLE_OCTOCLOCK) SET(octoclock_burner_sources octoclock_firmware_burner.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp_clock/octoclock/kk_ihex_read.c + ${CMAKE_SOURCE_DIR}/lib/utils/ihex.cpp ) ADD_DEFINITIONS(-DIHEX_USE_STDBOOL) diff --git a/host/utils/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp index c338cd818..326985df5 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 "kk_ihex_read.h" +#include "../lib/utils/ihex.hpp" #define MAX_FIRMWARE_SIZE 1024*120 #define BLOCK_SIZE 256 @@ -142,7 +142,7 @@ device_addrs_t bootloader_find(const std::string &ip_addr){ device_addrs_t addrs; boost::system_time comm_timeout = boost::get_system_time() + boost::posix_time::milliseconds(3000); - + while(boost::get_system_time() < comm_timeout){ UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_QUERY_CMD, pkt_out, len, octoclock_data); if(UHD_OCTOCLOCK_PACKET_MATCHES(OCTOCLOCK_QUERY_ACK, pkt_out, pkt_in, len) and @@ -292,22 +292,8 @@ 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); + ihex_reader hex_reader(hex_path); + hex_reader.to_bin_file(bin_path); } int UHD_SAFE_MAIN(UHD_UNUSED(int argc), UHD_UNUSED(char *argv[])){ |