aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp_clock/octoclock/kk_ihex_read.c
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/octoclock/kk_ihex_read.c
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/octoclock/kk_ihex_read.c')
-rw-r--r--host/lib/usrp_clock/octoclock/kk_ihex_read.c261
1 files changed, 261 insertions, 0 deletions
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;
+}