aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp_clock
diff options
context:
space:
mode:
authorNicholas Corgan <nick.corgan@ettus.com>2015-08-14 07:42:01 -0700
committerMartin Braun <martin.braun@ettus.com>2015-08-14 12:30:53 -0700
commitd35a0e28b6af67e4500b51c4739886f7544bca35 (patch)
tree64c04cd3b879d4898ecfcf4a52260ab8fa312d37 /host/lib/usrp_clock
parent8d6b63e1e86ae0f1ee8b084ea2db6d5b5b705179 (diff)
downloaduhd-d35a0e28b6af67e4500b51c4739886f7544bca35.tar.gz
uhd-d35a0e28b6af67e4500b51c4739886f7544bca35.tar.bz2
uhd-d35a0e28b6af67e4500b51c4739886f7544bca35.zip
octoclock: replaced Intel hex -> binary converter
Diffstat (limited to 'host/lib/usrp_clock')
-rw-r--r--host/lib/usrp_clock/octoclock/CMakeLists.txt4
-rw-r--r--host/lib/usrp_clock/octoclock/ihexcvt.cpp250
-rw-r--r--host/lib/usrp_clock/octoclock/ihexcvt.hpp22
-rw-r--r--host/lib/usrp_clock/octoclock/kk_ihex.h191
-rw-r--r--host/lib/usrp_clock/octoclock/kk_ihex_license.txt20
-rw-r--r--host/lib/usrp_clock/octoclock/kk_ihex_read.c261
-rw-r--r--host/lib/usrp_clock/octoclock/kk_ihex_read.h119
-rw-r--r--host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp54
8 files changed, 631 insertions, 290 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.")));