Browse Source

Supermogrify the thing into a lib

master
heck 2 years ago
parent
commit
e57077a3d1
  1. 1
      .gitignore
  2. 19
      src/Makefile
  3. 133
      src/fvhex2bin.c
  4. 43
      src/kk_ihex.h
  5. 53
      src/kk_ihex_read.c
  6. 102
      src/kk_ihex_read.h
  7. 140
      src/libfvhex2bin.c
  8. 3
      src/libfvhex2bin.h

1
.gitignore

@ -2,3 +2,4 @@
*.d *.d
src/fvhex2bin src/fvhex2bin
src/libfvhex2bin.a src/libfvhex2bin.a
/data/flangers.bin

19
src/Makefile

@ -1,32 +1,19 @@
TARGET_EXE=fvhex2bin TARGET_EXE=fvhex2bin
TARGET_LIB=lib$(TARGET_EXE).a TARGET_LIB=lib$(TARGET_EXE).a
# default config
#SYS_PREFIX?=/opt/local
# System
#SYS_INC_PATH?=$(SYS_PREFIX)/include
#SYS_LIB_PATH?=$(SYS_PREFIX)/lib
CFLAGS+=-std=c99 -MMD -MP -Wno-format-extra-args -Wno-deprecated-declarations -fvisibility=hidden CFLAGS+=-std=c99 -MMD -MP -Wno-format-extra-args -Wno-deprecated-declarations -fvisibility=hidden
#CFLAGS+=-isystem$(SYS_INC_PATH)
#LDFLAGS+=-DMACOSX_DEPLOYMENT_TARGET=11.00 -framework Foundation -framework IOKit -framework Security
#STATIC_LINK_LIBS=$(SYS_LIB_PATH)/libusb-1.0.a
SRC_ALL=$(wildcard *.c) SRC_ALL=$(wildcard *.c)
SRC_EXE=$(TARGET_EXE).c SRC_EXE=$(TARGET_EXE).c
SRC_LIB=$(filter-out $(SRC_EXE), $(SRC_ALL)) SRC_LIB=$(filter-out $(SRC_EXE), $(SRC_ALL))
#OBJ_EXE=$(subst .c,.o,$(SRC_EXE))
OBJ_LIB=$(subst .c,.o,$(SRC_LIB)) OBJ_LIB=$(subst .c,.o,$(SRC_LIB))
DEPENDS=$(subst .c,.d,$(SRC_ALL)) DEPENDS=$(subst .c,.d,$(SRC_ALL))
ifneq ($(MAKECMDGOALS),clean) ifneq ($(MAKECMDGOALS),clean)
-include $(DEPENDS) -include $(DEPENDS)
endif endif
.PHONY: all clean uninstall install .PHONY: all clean test
.DEFAULT_GOAL := all .DEFAULT_GOAL := all
all: $(TARGET_EXE) all: $(TARGET_EXE)
@ -39,6 +26,10 @@ $(TARGET_EXE): $(SRC_EXE) $(TARGET_LIB)
$(TARGET_LIB): $(OBJ_LIB) $(TARGET_LIB): $(OBJ_LIB)
$(AR) -cr $@ $^ $(AR) -cr $@ $^
test: all
./fvhex2bin -i ../data/flangers.hex -o ../data/flangers.bin
cmp -l ../data/flangers.bin ../data/flangers.hex.bin.target
clean: clean:
rm $(OBJ_LIB) $(TARGET_LIB) $(TARGET_EXE) $(DEPENDS) rm $(OBJ_LIB) $(TARGET_LIB) $(TARGET_EXE) $(DEPENDS)

133
src/fvhex2bin.c

@ -21,69 +21,33 @@
* Distribute freely, mark modified copies as such. * Distribute freely, mark modified copies as such.
*/ */
#include "kk_ihex_read.h" #include "libfvhex2bin.h"
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h>
#define AUTODETECT_ADDRESS (~0UL)
static FILE *outfile;
static unsigned long line_number = 1L;
static unsigned long file_position = 0L;
static unsigned long address_offset = 0UL;
static bool debug_enabled = 0;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct ihex_state ihex; char *infile = NULL;
FILE *infile = stdin; char *outfile = NULL;
ihex_count_t count;
char buf[256];
outfile = stdout;
while (--argc) { while (--argc) {
char *arg = *(++argv); char *arg = *(++argv);
if (arg[0] == '-' && arg[1] && arg[2] == '\0') { if (arg[0] == '-' && arg[1] && arg[2] == '\0') {
switch (arg[1]) { switch (arg[1]) {
case 'a':
if (--argc == 0) {
goto invalid_argument;
}
++argv;
errno = 0;
address_offset = strtoul(*argv, &arg, 0);
if (errno || arg == *argv) {
errno = errno ? errno : EINVAL;
goto argument_error;
}
break;
case 'A':
address_offset = AUTODETECT_ADDRESS;
break;
case 'i': case 'i':
if (--argc == 0) { if (--argc == 0) {
goto invalid_argument; goto invalid_argument;
} }
++argv; ++argv;
if (!(infile = fopen(*argv, "r"))) { infile = *argv;
goto argument_error;
}
break; break;
case 'o': case 'o':
if (--argc == 0) { if (--argc == 0) {
goto invalid_argument; goto invalid_argument;
} }
++argv; ++argv;
if (!(outfile = fopen(*argv, "wb"))) { outfile = *argv;
goto argument_error;
}
break;
case 'v':
debug_enabled = 1;
break; break;
case 'h': case 'h':
case '?': case '?':
@ -97,98 +61,13 @@ int main(int argc, char *argv[])
invalid_argument: invalid_argument:
(void)fprintf(stderr, "Invalid argument: %s\n", arg); (void)fprintf(stderr, "Invalid argument: %s\n", arg);
usage: usage:
(void)fprintf(stderr, "kk_ihex " KK_IHEX_VERSION " - Copyright (c) 2013-2015 Kimmo Kulovesi\n");
(void)fprintf( (void)fprintf(
stderr, stderr,
"Usage: ihex2bin ([-a <address_offset>]|[-A])" "Usage: ihex2bin ([-a <address_offset>]|[-A])"
" [-o <out.bin>] [-i <in.hex>] [-v]\n"); " [-o <out.bin>] [-i <in.hex>] [-v]\n");
return arg ? EXIT_FAILURE : EXIT_SUCCESS; return arg ? EXIT_FAILURE : EXIT_SUCCESS;
argument_error:
perror(*argv);
return EXIT_FAILURE;
}
ihex_read_at_address(
&ihex,
(address_offset != AUTODETECT_ADDRESS) ? (ihex_address_t)address_offset : 0);
while (fgets(buf, sizeof(buf), infile)) {
count = (ihex_count_t)strlen(buf);
ihex_read_bytes(&ihex, buf, count);
line_number += (count && buf[count - 1] == '\n');
}
ihex_end_read(&ihex);
if (infile != stdin) {
(void)fclose(infile);
} }
hex2bin(infile, outfile);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
ihex_bool_t ihex_data_read(struct ihex_state *ihex, ihex_record_type_t type, ihex_bool_t error)
{
if (error) {
(void)fprintf(stderr, "Checksum error on line %lu\n", line_number);
exit(EXIT_FAILURE);
}
if ((error = (ihex->length < ihex->line_length))) {
(void)fprintf(stderr, "Line length error on line %lu\n", line_number);
exit(EXIT_FAILURE);
}
if (!outfile) {
(void)fprintf(stderr, "Excess data after end of file record\n");
exit(EXIT_FAILURE);
}
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);
exit(EXIT_FAILURE);
}
}
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");
exit(EXIT_FAILURE);
}
}
file_position = address;
}
if (!fwrite(ihex->data, ihex->length, 1, outfile)) {
perror("fwrite");
exit(EXIT_FAILURE);
}
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;
}

43
src/kk_ihex.h

@ -111,7 +111,7 @@
#include <stdint.h> #include <stdint.h>
#ifdef IHEX_USE_STDBOOL #ifdef IHEX_USE_STDBOOL
#include <stdbool.h> #include <stdbool.h>
typedef bool ihex_bool_t; typedef bool ihex_bool_t;
#else #else
typedef uint_fast8_t ihex_bool_t; typedef uint_fast8_t ihex_bool_t;
@ -126,7 +126,7 @@ typedef int ihex_count_t;
// can be used to limit memory footprint on embedded systems, e.g., // can be used to limit memory footprint on embedded systems, e.g.,
// most programs with IHEX output use 32. // most programs with IHEX output use 32.
#ifndef IHEX_LINE_MAX_LENGTH #ifndef IHEX_LINE_MAX_LENGTH
#define IHEX_LINE_MAX_LENGTH 255 #define IHEX_LINE_MAX_LENGTH 255
#endif #endif
enum ihex_flags { enum ihex_flags {
@ -157,33 +157,34 @@ typedef uint8_t ihex_record_type_t;
#ifndef IHEX_DISABLE_SEGMENTS #ifndef IHEX_DISABLE_SEGMENTS
// Resolve segmented address (if any). It is the author's recommendation that // Resolve segmented address (if any). It is the author's recommendation that
// segmented addressing not be used (and indeed the write function of this // segmented addressing not be used (and indeed the write function of this
// library uses linear 32-bit addressing unless manually overridden). // library uses linear 32-bit addressing unless manually overridden).
// //
#define IHEX_LINEAR_ADDRESS(ihex) ((ihex)->address + (((ihex_address_t)((ihex)->segment)) << 4)) #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 // 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 // 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., // 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 // at 16 bits precision with wraparound) and the segment address only added
// afterwards. // afterwards.
// //
// To implement fully correct segmented addressing, compute the address // To implement fully correct segmented addressing, compute the address
// of _each byte_ with its index in `data` as follows: // 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)) #define IHEX_BYTE_ADDRESS(ihex, byte_index) \
((((ihex)->address + (byte_index)) & 0xFFFFU) + (((ihex_address_t)((ihex)->segment)) << 4))
#else // IHEX_DISABLE_SEGMENTS: #else // IHEX_DISABLE_SEGMENTS:
#define IHEX_LINEAR_ADDRESS(ihex) ((ihex)->address) #define IHEX_LINEAR_ADDRESS(ihex) ((ihex)->address)
#define IHEX_BYTE_ADDRESS(ihex, byte_index) ((ihex)->address + (byte_index)) #define IHEX_BYTE_ADDRESS(ihex, byte_index) ((ihex)->address + (byte_index))
#endif #endif
// The newline string (appended to every output line, e.g., "\r\n") // The newline string (appended to every output line, e.g., "\r\n")
#ifndef IHEX_NEWLINE_STRING #ifndef IHEX_NEWLINE_STRING
#define IHEX_NEWLINE_STRING "\n" #define IHEX_NEWLINE_STRING "\n"
#endif #endif
// See kk_ihex_read.h and kk_ihex_write.h for function declarations! // See kk_ihex_read.h and kk_ihex_write.h for function declarations!

53
src/kk_ihex_read.c

@ -10,9 +10,17 @@
#include "kk_ihex_read.h" #include "kk_ihex_read.h"
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#define IHEX_START ':' #define IHEX_START ':'
#define ADDRESS_HIGH_MASK ((ihex_address_t) 0xFFFF0000U) #define ADDRESS_HIGH_MASK ((ihex_address_t)0xFFFF0000U)
enum ihex_read_state { enum ihex_read_state {
READ_WAIT_FOR_START = 0, READ_WAIT_FOR_START = 0,
@ -32,8 +40,8 @@ enum ihex_read_state {
#define IHEX_READ_STATE_MASK 0x78 #define IHEX_READ_STATE_MASK 0x78
#define IHEX_READ_STATE_OFFSET 3 #define IHEX_READ_STATE_OFFSET 3
void void ihex_begin_read(struct ihex_state *const ihex)
ihex_begin_read (struct ihex_state * const ihex) { {
ihex->address = 0; ihex->address = 0;
#ifndef IHEX_DISABLE_SEGMENTS #ifndef IHEX_DISABLE_SEGMENTS
ihex->segment = 0; ihex->segment = 0;
@ -43,22 +51,22 @@ ihex_begin_read (struct ihex_state * const ihex) {
ihex->length = 0; ihex->length = 0;
} }
void void ihex_read_at_address(struct ihex_state *const ihex, ihex_address_t address)
ihex_read_at_address (struct ihex_state * const ihex, ihex_address_t address) { {
ihex_begin_read(ihex); ihex_begin_read(ihex);
ihex->address = address; ihex->address = address;
} }
#ifndef IHEX_DISABLE_SEGMENTS #ifndef IHEX_DISABLE_SEGMENTS
void void ihex_read_at_segment(struct ihex_state *const ihex, ihex_segment_t segment)
ihex_read_at_segment (struct ihex_state * const ihex, ihex_segment_t segment) { {
ihex_begin_read(ihex); ihex_begin_read(ihex);
ihex->segment = segment; ihex->segment = segment;
} }
#endif #endif
void void ihex_end_read(struct ihex_state *const ihex)
ihex_end_read (struct ihex_state * const ihex) { {
uint_fast8_t type = ihex->flags & IHEX_READ_RECORD_TYPE_MASK; uint_fast8_t type = ihex->flags & IHEX_READ_RECORD_TYPE_MASK;
uint_fast8_t sum; uint_fast8_t sum;
if ((sum = ihex->length) == 0 && type == IHEX_DATA_RECORD) { if ((sum = ihex->length) == 0 && type == IHEX_DATA_RECORD) {
@ -66,7 +74,7 @@ ihex_end_read (struct ihex_state * const ihex) {
} }
{ {
// compute and validate checksum // compute and validate checksum
const uint8_t * const eptr = ihex->data + sum; const uint8_t *const eptr = ihex->data + sum;
const uint8_t *r = ihex->data; const uint8_t *r = ihex->data;
sum += type + (ihex->address & 0xFFU) + ((ihex->address >> 8) & 0xFFU); sum += type + (ihex->address & 0xFFU) + ((ihex->address >> 8) & 0xFFU);
while (r != eptr) { while (r != eptr) {
@ -74,14 +82,14 @@ ihex_end_read (struct ihex_state * const ihex) {
} }
sum = (~sum + 1U) ^ *eptr; // *eptr is the received checksum sum = (~sum + 1U) ^ *eptr; // *eptr is the received checksum
} }
if (ihex_data_read(ihex, type, (uint8_t) sum)) { if (ihex_data_read(ihex, type, (uint8_t)sum)) {
if (type == IHEX_EXTENDED_LINEAR_ADDRESS_RECORD) { if (type == IHEX_EXTENDED_LINEAR_ADDRESS_RECORD) {
ihex->address &= 0xFFFFU; ihex->address &= 0xFFFFU;
ihex->address |= (((ihex_address_t) ihex->data[0]) << 24) | ihex->address |= (((ihex_address_t)ihex->data[0]) << 24) |
(((ihex_address_t) ihex->data[1]) << 16); (((ihex_address_t)ihex->data[1]) << 16);
#ifndef IHEX_DISABLE_SEGMENTS #ifndef IHEX_DISABLE_SEGMENTS
} else if (type == IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD) { } else if (type == IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD) {
ihex->segment = (ihex_segment_t) ((ihex->data[0] << 8) | ihex->data[1]); ihex->segment = (ihex_segment_t)((ihex->data[0] << 8) | ihex->data[1]);
#endif #endif
} }
} }
@ -89,9 +97,9 @@ ihex_end_read (struct ihex_state * const ihex) {
ihex->flags = 0; ihex->flags = 0;
} }
void void ihex_read_byte(struct ihex_state *const ihex, const char byte)
ihex_read_byte (struct ihex_state * const ihex, const char byte) { {
uint_fast8_t b = (uint_fast8_t) byte; uint_fast8_t b = (uint_fast8_t)byte;
uint_fast8_t len = ihex->length; uint_fast8_t len = ihex->length;
uint_fast8_t state = (ihex->flags & IHEX_READ_STATE_MASK); uint_fast8_t state = (ihex->flags & IHEX_READ_STATE_MASK);
ihex->flags ^= state; // turn off the old state ihex->flags ^= state; // turn off the old state
@ -138,11 +146,11 @@ ihex_read_byte (struct ihex_state * const ihex, const char byte) {
case (READ_ADDRESS_MSB_LOW >> 1): case (READ_ADDRESS_MSB_LOW >> 1):
// high byte of 16-bit address // high byte of 16-bit address
ihex->address &= ADDRESS_HIGH_MASK; // clear the 16-bit address ihex->address &= ADDRESS_HIGH_MASK; // clear the 16-bit address
ihex->address |= ((ihex_address_t) b) << 8U; ihex->address |= ((ihex_address_t)b) << 8U;
break; break;
case (READ_ADDRESS_LSB_LOW >> 1): case (READ_ADDRESS_LSB_LOW >> 1):
// low byte of 16-bit address // low byte of 16-bit address
ihex->address |= (ihex_address_t) b; ihex->address |= (ihex_address_t)b;
break; break;
case (READ_RECORD_TYPE_LOW >> 1): case (READ_RECORD_TYPE_LOW >> 1):
// record type // record type
@ -169,13 +177,10 @@ save_read_state:
ihex->flags |= state << IHEX_READ_STATE_OFFSET; ihex->flags |= state << IHEX_READ_STATE_OFFSET;
} }
void void ihex_read_bytes(struct ihex_state *restrict ihex, const char *restrict data, ihex_count_t count)
ihex_read_bytes (struct ihex_state * restrict ihex, {
const char * restrict data,
ihex_count_t count) {
while (count > 0) { while (count > 0) {
ihex_read_byte(ihex, *data++); ihex_read_byte(ihex, *data++);
--count; --count;
} }
} }

102
src/kk_ihex_read.h

@ -40,67 +40,65 @@
#define KK_IHEX_READ_H #define KK_IHEX_READ_H
#ifdef __cplusplus #ifdef __cplusplus
#ifndef restrict #ifndef restrict
#define restrict #define restrict
#endif #endif
extern "C" { extern "C" {
#endif #endif
#include "kk_ihex.h" #include "kk_ihex.h"
// Begin reading at address 0 // Begin reading at address 0
void ihex_begin_read(struct ihex_state *ihex); void ihex_begin_read(struct ihex_state *ihex);
// Begin reading at `address` (the lowest 16 bits of which will be ignored); // 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 // 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 // are not specified in the input data and they are non-zero
void ihex_read_at_address(struct ihex_state *ihex, void ihex_read_at_address(struct ihex_state *ihex, ihex_address_t address);
ihex_address_t address);
// Read a single character // Read a single character
void ihex_read_byte(struct ihex_state *ihex, char chr); void ihex_read_byte(struct ihex_state *ihex, char chr);
// Read `count` bytes from `data` // Read `count` bytes from `data`
void ihex_read_bytes(struct ihex_state * restrict ihex, void ihex_read_bytes(struct ihex_state *restrict ihex, const char *restrict data, ihex_count_t count);
const char * restrict data,
ihex_count_t count);
// End reading (may call `ihex_data_read` if there is data waiting) // End reading (may call `ihex_data_read` if there is data waiting)
void ihex_end_read(struct ihex_state *ihex); void ihex_end_read(struct ihex_state *ihex);
// Called when a complete line has been read, the record type of which is // 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`, // passed as `type`. The `ihex` structure will have its fields `data`,
// `line_length`, `address`, and `segment` set appropriately. In case // `line_length`, `address`, and `segment` set appropriately. In case
// of reading an `IHEX_EXTENDED_LINEAR_ADDRESS_RECORD` or an // of reading an `IHEX_EXTENDED_LINEAR_ADDRESS_RECORD` or an
// `IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD` the record's data is not // `IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD` the record's data is not
// yet parsed - it will be parsed into the `address` or `segment` field // yet parsed - it will be parsed into the `address` or `segment` field
// only if `ihex_data_read` returns `true`. This allows manual handling // only if `ihex_data_read` returns `true`. This allows manual handling
// of extended addresses by parsing the `ihex->data` bytes. // of extended addresses by parsing the `ihex->data` bytes.
// //
// Possible error cases include checksum mismatch (which is indicated // Possible error cases include checksum mismatch (which is indicated
// as an argument), and excessive line length (in case this has been // as an argument), and excessive line length (in case this has been
// compiled with `IHEX_LINE_MAX_LENGTH` less than 255) which is indicated // compiled with `IHEX_LINE_MAX_LENGTH` less than 255) which is indicated
// by `line_length` greater than `length`. Unknown record types and // by `line_length` greater than `length`. Unknown record types and
// other erroneous data is usually silently ignored by this minimalistic // other erroneous data is usually silently ignored by this minimalistic
// parser. (It is recommended to compute a hash over the complete data // parser. (It is recommended to compute a hash over the complete data
// once received and verify that against the source.) // once received and verify that against the source.)
// //
// Example implementation: // Example implementation:
// //
// ihex_bool_t ihex_data_read(struct ihex_state *ihex, // ihex_bool_t ihex_data_read(struct ihex_state *ihex,
// ihex_record_type_t type, // ihex_record_type_t type,
// ihex_bool_t error) { // ihex_bool_t error) {
// error = error || (ihex->length < ihex->line_length); // error = error || (ihex->length < ihex->line_length);
// if (type == IHEX_DATA_RECORD && !error) { // if (type == IHEX_DATA_RECORD && !error) {
// (void) fseek(outfile, IHEX_LINEAR_ADDRESS(ihex), SEEK_SET); // (void) fseek(outfile, IHEX_LINEAR_ADDRESS(ihex), SEEK_SET);
// (void) fwrite(ihex->data, 1, ihex->length, outfile); // (void) fwrite(ihex->data, 1, ihex->length, outfile);
// } else if (type == IHEX_END_OF_FILE_RECORD) { // } else if (type == IHEX_END_OF_FILE_RECORD) {
// (void) fclose(outfile); // (void) fclose(outfile);
// } // }
// return !error; // return !error;
// } // }
// //
extern ihex_bool_t ihex_data_read(struct ihex_state *ihex, extern ihex_bool_t ihex_data_read(
struct ihex_state *ihex,
ihex_record_type_t type, ihex_record_type_t type,
ihex_bool_t checksum_mismatch); ihex_bool_t checksum_mismatch);
@ -108,7 +106,7 @@ extern ihex_bool_t ihex_data_read(struct ihex_state *ihex,
// is not specified in the input data and it is non-zero. // is not specified in the input data and it is non-zero.
// //
#ifndef IHEX_DISABLE_SEGMENTS #ifndef IHEX_DISABLE_SEGMENTS
void ihex_read_at_segment(struct ihex_state *ihex, ihex_segment_t segment); void ihex_read_at_segment(struct ihex_state *ihex, ihex_segment_t segment);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

140
src/libfvhex2bin.c

@ -0,0 +1,140 @@
/*
* ihex2bin.c: Read Intel HEX format, write binary data.
*
* By default reads from stdin and writes to stdout. The command-line
* options `-i` and `-o` can be used to specify the input and output
* file, respectively. Specifying an output file allows sparse writes.
*
* NOTE: Many Intel HEX files produced by compilers/etc have data
* beginning at an address greater than zero, potentially causing very
* unnecessarily large files to be created. The command-line option
* `-a` can be used to specify the start address of the output file,
* i.e., the value will be subtracted from the IHEX addresses (the
* result must not be negative).
*
* Alternatively, the command-line option `-A` sets the address offset
* to the first address that would be written (i.e., first byte of
* data written will be at address 0).
*
* Copyright (c) 2013-2019 Kimmo Kulovesi, https://arkku.com
* Provided with absolutely no warranty, use at your own risk only.
* Distribute freely, mark modified copies as such.
*/
#include "kk_ihex_read.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define AUTODETECT_ADDRESS (~0UL)
static unsigned long line_number = 1L;
static unsigned long file_position = 0L;
static unsigned long address_offset = 0UL;
static bool debug_enabled = 0;
static FILE *infile = NULL;
static FILE *outfile = NULL;
int hex2bin(const char *infilename, const char *outfilename)
{
int ret = 0;
if (!(infile = fopen(infilename, "r"))) {
return 255;
}
if (!(outfile = fopen(outfilename, "wb"))) {
return 255;
}
struct ihex_state ihex;
ihex_count_t count;
char buf[256];
ihex_read_at_address(
&ihex,
(address_offset != AUTODETECT_ADDRESS) ? (ihex_address_t)address_offset : 0);
while (fgets(buf, sizeof(buf), infile)) {
count = (ihex_count_t)strlen(buf);
ihex_read_bytes(&ihex, buf, count);
line_number += (count && buf[count - 1] == '\n');
}
ihex_end_read(&ihex);
if (infile != stdin) {
(void)fclose(infile);
}
return ret;
}
ihex_bool_t ihex_data_read(struct ihex_state *ihex, ihex_record_type_t type, ihex_bool_t error)
{
if (error) {
(void)fprintf(stderr, "Checksum error on line %lu\n", line_number);
exit(EXIT_FAILURE);
}
if ((error = (ihex->length < ihex->line_length))) {
(void)fprintf(stderr, "Line length error on line %lu\n", line_number);
exit(EXIT_FAILURE);
}
if (!outfile) {
(void)fprintf(stderr, "Excess data after end of file record\n");
exit(EXIT_FAILURE);
}
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);
exit(EXIT_FAILURE);
}
}
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");
exit(EXIT_FAILURE);
}
}
file_position = address;
}
if (!fwrite(ihex->data, ihex->length, 1, outfile)) {
perror("fwrite");
exit(EXIT_FAILURE);
}
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;
}

3
src/libfvhex2bin.h

@ -0,0 +1,3 @@
#pragma once
int hex2bin(const char *infilename, const char *outfile);
Loading…
Cancel
Save