diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-06-15 12:07:27 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-06-15 12:07:27 -0600 |
commit | 2fba86a7717ecd534d94189fdf8734bf8d3ec91f (patch) | |
tree | ac8b2b6b18816b4d4e04c41dc43b3379ea860e46 /apps/system/hex2bin | |
parent | 4d332f0bcc2f1feeec8b3344e694e66095b61080 (diff) | |
download | px4-nuttx-2fba86a7717ecd534d94189fdf8734bf8d3ec91f.tar.gz px4-nuttx-2fba86a7717ecd534d94189fdf8734bf8d3ec91f.tar.bz2 px4-nuttx-2fba86a7717ecd534d94189fdf8734bf8d3ec91f.zip |
Add conversion of Intel HEX to binary
Diffstat (limited to 'apps/system/hex2bin')
-rw-r--r-- | apps/system/hex2bin/.gitignore | 11 | ||||
-rw-r--r-- | apps/system/hex2bin/Kconfig | 53 | ||||
-rw-r--r-- | apps/system/hex2bin/Makefile | 108 | ||||
-rw-r--r-- | apps/system/hex2bin/hex2bin.c | 685 | ||||
-rw-r--r-- | apps/system/hex2bin/hex2bin_main.c | 266 |
5 files changed, 1123 insertions, 0 deletions
diff --git a/apps/system/hex2bin/.gitignore b/apps/system/hex2bin/.gitignore new file mode 100644 index 000000000..83bd7b811 --- /dev/null +++ b/apps/system/hex2bin/.gitignore @@ -0,0 +1,11 @@ +/Make.dep +/.depend +/.built +/*.asm +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src +/*.obj diff --git a/apps/system/hex2bin/Kconfig b/apps/system/hex2bin/Kconfig new file mode 100644 index 000000000..ae01cfed2 --- /dev/null +++ b/apps/system/hex2bin/Kconfig @@ -0,0 +1,53 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +config SYSTEM_HEX2BIN + bool "Intel HEX Convertion" + default n + ---help--- + Enable support for a logic to convert Intel HEX format to binary. + +if SYSTEM_HEX2BIN + +config SYSTEM_HEX2BIN_BUILTIN + bool "NSH Built-In" + default n + depends on NSH_BUILTIN_APPS + ---help--- + By default, a flexible hex2bin library function built. An NSH + builtin function can also be generated to convert Intel HEX file + to binary files. + +if SYSTEM_HEX2BIN_BUILTIN + +config SYSTEM_HEX2BIN_BASEADDR + hex "Binary base address" + default 0x00000000 + ---help--- + The default value of the base address argument. Saves typing. + +config SYSTEM_HEX2BIN_ENDPADDR + hex "Binary base address" + default 0x00000000 + ---help--- + The default value of the end (plus 1) address argument. Saves typing. + +config SYSTEM_HEX2BIN_SWAP + int "Binary base address" + default 0 + range 0 2 + ---help--- + The default value of the swap argument. (0) No swap, (1) swap bytes + in 16-bit values, or (2) swap tbytes in 32-bit values. + +endif # SYSTEM_HEX2BIN_BUILTIN + +config SYSTEM_HEX2BIN_DEBUG + bool "Hex2bin detailed error output" + default n + ---help--- + Enable extended error output. + +endif # SYSTEM_HEX2BIN diff --git a/apps/system/hex2bin/Makefile b/apps/system/hex2bin/Makefile new file mode 100644 index 000000000..ce50879b1 --- /dev/null +++ b/apps/system/hex2bin/Makefile @@ -0,0 +1,108 @@ +############################################################################ +# apps/system/hex2bin/Makefile +# +# Copyright (C) 2014 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <gnutt@nuttx.org> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# I2C tool + +ASRCS = +CSRCS = hex2bin.c hex2bin_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + BIN = ..\\..\\libapps$(LIBEXT) +else + BIN = ../../libapps$(LIBEXT) +endif +endif + +ROOTDEPPATH = --dep-path . +VPATH = + +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 768 + +# Build targets + +all: .built +.PHONY: context .depend depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + $(Q) touch .built + +# Register application + +ifeq ($(CONFIG_SYSTEM_HEX2BIN_BUILTINS),y) +$(BUILTIN_REGISTRY)$(DELIM)hex2bin.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,"hex2bin",$(PRIORITY),$(STACKSIZE),hex2bin_main) + +context: $(BUILTIN_REGISTRY)$(DELIM)hex2bin.bdat +else +context: +endif + +.depend: Makefile $(SRCS) + $(Q) $(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + $(Q) touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep + diff --git a/apps/system/hex2bin/hex2bin.c b/apps/system/hex2bin/hex2bin.c new file mode 100644 index 000000000..28eb9df50 --- /dev/null +++ b/apps/system/hex2bin/hex2bin.c @@ -0,0 +1,685 @@ +/**************************************************************************** + * apps/system/hex2bin.c + * Reference: http://en.wikipedia.org/wiki/Intel_HEX + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdint.h> +#include <errno.h> + +#include <nuttx/streams.h> +#include <apps/hex2bin.h> + +#ifdef CONFIG_SYSTEM_HEX2BIN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* ASCII record sizes */ + +#define BYTECOUNT_ASCSIZE 2 +#define ADDRESS_ASCSIZE 4 +#define RECTYPE_ASCSIZE 2 + +#define BYTECOUNT_LINENDX (0) +#define ADDRESS_LINENDX (BYTECOUNT_LINENDX + BYTECOUNT_ASCSIZE) +#define RECTYPE_LINENDX (ADDRESS_LINENDX + ADDRESS_ASCSIZE) +#define DATA_LINENDX (RECTYPE_LINENDX + RECTYPE_ASCSIZE) +#define HEADER_ASCSIZE DATA_LINENDX + +#define CHECKSUM_ASCSIZE 2 +#define TRAILER_SIZE (CHECKSUM_ASCSIZE) + +#define MAXDATA_BINSIZE 255 +#define RECORD_ASCSIZE(n) (HEADER_ASCSIZE + TRAILER_SIZE + 2*(n)) +#define MAXRECORD_ASCSIZE RECORD_ASCSIZE(MAXDATA_BINSIZE) +#define MINRECORD_ASCSIZE RECORD_ASCSIZE(0) +#define LINE_ALLOC MAXRECORD_ASCSIZE + +/* Binary record sizes */ + +#define BYTECOUNT_BINSIZE 1 +#define ADDRESS_BINSIZE 2 +#define RECTYPE_BINSIZE 1 + +#define BYTECOUNT_BINNDX (0) +#define ADDRESS_BINNDX (BYTECOUNT_BINNDX + BYTECOUNT_BINSIZE) +#define RECTYPE_BINNDX (ADDRESS_BINNDX + ADDRESS_BINSIZE) +#define DATA_BINNDX (RECTYPE_BINNDX + RECTYPE_BINSIZE) +#define HEADER_BINSIZE DATA_BINNDX + +#define CHECKSUM_BINSIZE 1 +#define TRAILER_BINSIZE CHECKSUM_BINSIZE + +#define RECORD_BINSIZE(n) (HEADER_BINSIZE + TRAILER_BINSIZE + (n)) +#define MAXRECORD_BINSIZE RECORD_ASCSIZE(MAXDATA_BINSIZE) +#define MINRECORD_BKINSIZE RECORD_ASCSIZE(0) +#define BIN_ALLOC MAXRECORD_BINSIZE + +/* Record start code */ + +#define RECORD_STARTCODE ':' + +/* Record Types */ + +#define RECORD_DATA 0 /* Data */ +#define RECORD_EOF 1 /* End of file */ +#define RECORD_EXT_SEGADDR 2 /* Extended segment address record */ +#define RECORD_START_SEGADDR 3 /* Start segment address record */ +#define RECORD_EXT_LINADDR 4 /* Extended linear address record */ +#define RECORD_START_LINADDR 5 /* Start linear address record */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nibble2bin + ****************************************************************************/ + +static int nibble2bin(uint8_t ascii) +{ + if (ascii >= '0' && ascii <= '9') + { + return (ascii - 0x30); + } + else if (ascii >= 'a' && ascii <= 'f') + { + return (ascii - 'a' + 10); + } + else if (ascii >= 'A' && ascii <= 'F') + { + return (ascii - 'A' + 10); + } + + return -EINVAL; +} + +/**************************************************************************** + * Name: byte2bin + ****************************************************************************/ + +static int byte2bin(FAR const uint8_t *ascii) +{ + int nibble; + int byte; + + /* Get the MS nibble (big endian order) */ + + nibble = nibble2bin(*ascii++); + if (nibble < 0) + { + return nibble; + } + + byte = (nibble << 4); + + /* Get the MS nibble */ + + nibble = nibble2bin(*ascii); + if (nibble < 0) + { + return nibble; + } + + byte |= nibble; + return byte; +} + +/**************************************************************************** + * Name: word2bin + ****************************************************************************/ + +#if 0 /* Not used */ +static int word2bin(FAR const char *ascii) +{ + int byte; + int word; + + /* Get the MS byte (big endian order) */ + + byte = word2bin(ascii); + if (byte < 0) + { + return byte; + } + + word = (byte << 8); + + /* Get the MS byte */ + + byte = word2bin(ascii + 2); + if (byte < 0) + { + return byte; + } + + word |= byte; + return word; +} +#endif + +/**************************************************************************** + * Name: data2bin + ****************************************************************************/ + +int data2bin(FAR uint8_t* dest, FAR const uint8_t *src, int nbytes) +{ + int byte; + + /* An even number of source bytes is expected */ + + if ((nbytes & 1) != 0) + { + return -EINVAL; + } + + /* Convert src bytes in groups of 2, writing one byte to the output on each + * pass through the loop. */ + + while (nbytes-- > 0) + { + /* Get the MS nibble (big endian order) */ + + byte = byte2bin(src); + if (byte < 0) + { + return byte; + } + + src += 2; + + /* And write the byte to the destination */ + + *dest++ = byte; + } + + return OK; +} + +/**************************************************************************** + * Name: readstream + ****************************************************************************/ + +static int readstream(FAR struct lib_instream_s *instream, + FAR uint8_t *line, unsigned int lineno) +{ + int ch = instream->get(instream); + int nbytes = 0; + + /* Skip until the beginning of line start code is encountered */ + + while (ch != RECORD_STARTCODE && ch != EOF) + { + ch = instream->get(instream); + } + + /* Read until the end of line is encountered */ + + while (ch != EOF && nbytes < (MAXRECORD_ASCSIZE-1)) + { +#if defined(CONFIG_EOL_IS_LF) + if (ch == '\n') + { + *line = '\0'; + return nbytes; + } + +#elif defined(CONFIG_EOL_IS_BOTH_CRLF) + if (ch == '\r') + { + continue; + } + else if (ch == '\n') + { + *line = '\0'; + return nbytes; + } +#elif defined(CONFIG_EOL_IS_CR) + if (ch == '\r') + { + *line = '\0'; + return nbytes; + } +#elif CONFIG_EOL_IS_EITHER_CRLF + if (ch == '\n' || ch == '\r') + { + *line = '\0'; + return nbytes; + } +#endif + /* Only hex data goes into the line buffer */ + + else if (isxdigit(ch)) + { + *line++ = ch; + nbytes++; + } + else + { + hex2bin_debug("Line %u ERROR: Unexpected character %c[%02x] in stream\n", + lineno, isprint(ch) ? ch : '.', ch); + break; + } + } + + /* Some error occurred: Unexpected EOF, line too long, or bad character in + * stream + */ + + hex2bin_debug("Line %u ERROR: Failed to read line. %d characters read\n", + lineno, nbytes); + return EOF; +} + +/**************************************************************************** + * Name: hex2bin_swap16 and hex2bin_swap32 + ****************************************************************************/ + +static inline void hex2bin_swap16(FAR uint8_t *bin, int bytecount) +{ + for (; bytecount > 0; bytecount -= 2) + { + uint8_t b0 = bin[0]; + uint8_t b1 = bin[1]; + + *bin++ = b1; + *bin++ = b0; + } +} + +static inline void hex2bin_swap32(FAR uint8_t *bin, int bytecount) +{ + for (; bytecount > 0; bytecount -= 4) + { + uint8_t b0 = bin[0]; + uint8_t b1 = bin[1]; + uint8_t b2 = bin[2]; + uint8_t b3 = bin[3]; + + *bin++ = b3; + *bin++ = b2; + *bin++ = b1; + *bin++ = b0; + } +} + +/**************************************************************************** + * Name: writedata + ****************************************************************************/ + +static inline void writedata(FAR struct lib_sostream_s *outstream, + FAR uint8_t *bin, int bytecount) +{ + for (; bytecount > 0; bytecount--) + { + outstream->put(outstream, *bin++); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hex2bin + * + * Description: + * Read the Intel HEX ASCII data provided on the serial IN stream and write + * the binary to the seek-able serial OUT stream. + * + * These streams may be files or, in another usage example, the IN stream + * could be a serial port and the OUT stream could be a memory stream. This + * would decode and write the serial input to memory. + * + * Input Parameters: + * instream - The incoming stream from which Intel HEX data will be + * received. + * outstream - The outgoing stream in which binary data will be written. + * baseaddr - The base address of the outgoing stream. Seeking in the + * output stream will be relative to this address. + * endpaddr - The end address (plus 1) of the outgoing stream. This + * value is used only for range checking. endpaddr must + * be larger than baseaddr. A zero value for endpaddr + * disables range checking. + * swap - Controls byte ordering. See enum hex2bin_swap_e for + * description of the values. + * + * Returned Value + * Zero (OK) is returned on success; a negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int hex2bin(FAR struct lib_instream_s *instream, + FAR struct lib_sostream_s *outstream, uint32_t baseaddr, + uint32_t endpaddr, enum hex2bin_swap_e swap) +{ + FAR uint8_t *alloc; + FAR uint8_t *line; + FAR uint8_t *bin; + int nbytes; + int bytecount; + uint32_t address; + uint32_t expected; + uint16_t extension; + uint16_t address16; + uint8_t checksum; + unsigned int lineno; + int i; + int ret = OK; + + /* Allocate buffer memory */ + + alloc = (FAR uint8_t *)malloc(LINE_ALLOC + BIN_ALLOC); + if (alloc == NULL) + { + hex2bin_debug("ERROR: Failed to allocate memory\n"); + return -ENOMEM; + } + + line = alloc; + bin = &alloc[LINE_ALLOC]; + + extension = 0; + expected = 0; + lineno = 0; + + while ((nbytes = readstream(instream, line, lineno)) != EOF) + { + /* Increment the line number */ + + lineno++; + + /* Did we read enough data to do anything? */ + + if (nbytes < MINRECORD_ASCSIZE) + { + hex2bin_debug("Line %u ERROR: Record too short: %d\n", + lineno, nbytes); + goto errout_with_einval; + } + + /* We should always read an even number of bytes */ + + if ((nbytes & 1) != 0) + { + hex2bin_debug("Line %u ERROR: Record length is odd: %d\n", + lineno, nbytes); + goto errout_with_einval; + } + + /* Get the data byte count */ + + bytecount = byte2bin(&line[BYTECOUNT_LINENDX]); + if (bytecount < 0) + { + hex2bin_debug("Line %u ERROR: Failed to read bytecount: %d\n", + lineno, bytecount); + ret = bytecount; + goto errout_with_buffers; + } + + /* Verify that the bytecount matches the length of the record */ + + if (RECORD_ASCSIZE(bytecount) != nbytes) + { + hex2bin_debug("Line %u ERROR: Expected %d bytes, read %d\n", + lineno, RECORD_ASCSIZE(bytecount), nbytes); + goto errout_with_einval; + } + + /* Convert the entire line to binary. We need to do this for + * checksum calculation which includes the entire line (minus + * the start code and the checksum at the end of the line itself) + */ + + ret = data2bin(line, bin, nbytes); + if (ret < 0) + { + hex2bin_debug("Line %u ERROR: Failed to convert line to binary: %d\n", + lineno, ret); + goto errout_with_buffers; + } + + /* Calculate and verify the checksum over all of the data */ + + checksum = 0; + for (i = 0; i < bytecount; i++) + { + checksum += bin[i]; + } + + if (checksum != 0) + { + hex2bin_debug("Line %u ERROR: Bad checksum %02x\n", + lineno, checksum); + goto errout_with_einval; + } + + /* Get the 16-bit (unextended) address from the record */ + + address16 = (uint16_t)bin[ADDRESS_BINNDX] << 8 | + (uint16_t)bin[ADDRESS_BINNDX+1]; + + /* Handle the record by its record type */ + + switch (bin[RECTYPE_BINNDX]) + { + case RECORD_DATA: /* Data */ + { + /* Swap data in place in the binary buffer as required */ + + switch (swap) + { + case HEX2BIN_NOSWAP: /* No swap, stream is the correct byte order */ + break; + + case HEX2BIN_SWAP16: /* Swap bytes in 16-bit values */ + { + if ((bytecount & 1) != 0) + { + hex2bin_debug("Line %d ERROR: Byte count %d is not a multiple of 2\n", + lineno, bytecount); + goto errout_with_einval; + } + + /* Do the byte swap */ + + hex2bin_swap16(bin, bytecount); + } + break; + + case HEX2BIN_SWAP32: /* Swap bytes in 32-bit values */ + { + if ((bytecount & 3) != 0) + { + hex2bin_debug("Line %d ERROR: Byte count %d is not a multiple of 4\n", + lineno, bytecount); + goto errout_with_einval; + } + + /* Do the byte swap */ + + hex2bin_swap32(bin, bytecount); + } + break; + + default: + { + hex2bin_debug("ERROR: Invalid swap argument: %d\n", swap); + goto errout_with_einval; + } + } + + /* Get and verify the full 32-bit address */ + + address = ((uint32_t)extension << 16) | (uint32_t)address16; + if (address < baseaddr || (endpaddr != 0 && address >= endpaddr)) + { + hex2bin_debug("Line %d ERROR: Extended address %08lx is out of range\n", + lineno, (unsigned long)address); + goto errout_with_einval; + } + + /* Seek to the correct position in the OUT stream */ + + if (address != expected) + { + off_t pos = outstream->seek(outstream, address - baseaddr, SEEK_SET); + if (pos == (off_t)-1) + { + hex2bin_debug("Line %u ERROR: Seek to address %08lu failed\n", + lineno, (unsigned long)address); + ret = -ESPIPE; + goto errout_with_buffers; + } + } + + /* Transfer data to the OUT stream */ + + writedata(outstream, bin, bytecount); + } + break; + + case RECORD_EOF: /* End of file */ + /* End Of File record. Must occur exactly once per file in the + * last line of the file. The byte count is 00 and the data field + * is empty. Usually the address field is also 0000. + */ + + if (bytecount == 0) + { + ret = OK; + goto exit_with_buffers; + } + + hex2bin_debug("Line %u ERROR: Nonzero bytecount %d in EOF\n", + lineno, bytecount); + goto errout_with_einval; + + case RECORD_EXT_SEGADDR: /* Extended segment address record */ + /* The address specified by the data field is multiplied by 16 + * (shifted 4 bits left) and added to the subsequent data record + * addresses. This allows addressing of up to a megabyte of + * address space. The address field of this record has to be + * 0000, the byte count is 02 (the segment is 16-bit). The + * least significant hex digit of the segment address is always + * 0. + */ + + if (bytecount != 2 || address16 != 0 || bin[1] != 0) + { + hex2bin_debug("Line %u ERROR: Invalid segment address\n", + lineno); + hex2bin_debug(" bytecount=%d address=%04x segment=%02x%02x\n", + bytecount, address16, bin[0], bin[1]); + goto errout_with_einval; + } + + extension = (uint16_t)bin[0]; + break; + + case RECORD_START_SEGADDR: /* Start segment address record */ + /* For 80x86 processors, it specifies the initial content of + * the CS:IP registers. The address field is 0000, the byte + * count is 04, the first two bytes are the CS value, the + * latter two are the IP value. + */ + + break; + + case RECORD_EXT_LINADDR: /* Extended linear address record */ + /* The address field is 0000, the byte count is 02. The two + * data bytes (two hex digit pairs in big endian order) + * represent the upper 16 bits of the 32 bit address for + * all subsequent 00 type records until the next 04 type + * record comes. If there is not a 04 type record, the + * upper 16 bits default to 0000. To get the absolute + * address for subsequent 00 type records, the address + * specified by the data field of the most recent 04 record + * is added to the 00 record addresses. + */ + + if (bytecount != 2 || address16 != 0) + { + hex2bin_debug("Line %u ERROR: Invalid linear address\n", + lineno); + hex2bin_debug(" bytecount=%d address=%04x\n", + bytecount, address16); + goto errout_with_einval; + } + + extension = (uint16_t)bin[0] << 8 | (uint16_t)bin[1]; + break; + + case RECORD_START_LINADDR: /* Start linear address record */ + /* The address field is 0000, the byte count is 04. The 4 + * data bytes represent the 32-bit value loaded into the EIP + * register of the 80386 and higher CPU. + */ + + break; + + default: + break; + } + } + + hex2bin_debug("ERROR: No EOF record found\n"); + +errout_with_einval: + ret = -EINVAL; + +errout_with_buffers: +exit_with_buffers: + free(alloc); + return -ret; +} + +#endif /* CONFIG_SYSTEM_HEX2BIN */ diff --git a/apps/system/hex2bin/hex2bin_main.c b/apps/system/hex2bin/hex2bin_main.c new file mode 100644 index 000000000..660cd5723 --- /dev/null +++ b/apps/system/hex2bin/hex2bin_main.c @@ -0,0 +1,266 @@ +/**************************************************************************** + * apps/system/hex2bin_main.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> + +#include <nuttx/streams.h> +#include <apps/hex2bin.h> + +#ifdef CONFIG_SYSTEM_HEX2BIN_BUILTIN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: show_usage + ****************************************************************************/ + +void show_usage(FAR const char *progname, int exitcode) +{ + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\t%s [OPTIONS] <hexfile> <binfile>\n"); + fprintf(stderr, "\t%s -h\n"); + fprintf(stderr, "Where:\n"); + fprintf(stderr, "\t<hexfile>:\n"); + fprintf(stderr, "\t\tThe file containing the Intel HEX data to be converted.\n"); + fprintf(stderr, "\t<binfile>:\n"); + fprintf(stderr, "\t\tThe output file to be created contained the converted\n"); + fprintf(stderr, "\t\tbinary data.\n"); + fprintf(stderr, "\t-h:\n"); + fprintf(stderr, "\t\tPrints this message and exits\n"); + fprintf(stderr, "And [OPTIONS] include:\n"); + fprintf(stderr, "\t-s <start address>\n"); + fprintf(stderr, "\t\tSets the start address of the binary output. This value\n"); + fprintf(stderr, "\t\tis used to (1) calculate offsets into the output stream,\n"); + fprintf(stderr, "\t\tand (2) for error checking. Default: 0x%08x\n", + CONFIG_SYSTEM_HEX2BIN_BASEADDR); + fprintf(stderr, "\t-e <end address>\n"); + fprintf(stderr, "\t\tSets the maximum address (plus 1) of the binary output.\n"); + fprintf(stderr, "\t\tThis value is used to only for error checking. Default:\n"); + fprintf(stderr, "\t\t0x%08x\n", CONFIG_SYSTEM_HEX2BIN_ENDPADDR); + fprintf(stderr, "\t\tno error checking\n"); + fprintf(stderr, "\t-w <swap code>\n"); + fprintf(stderr, "\t\t(0) No swap, (1) swap bytes in 16-bit values, or (3) swap\n"); + fprintf(stderr, "\t\tbytes in 32-bit values. Default: %d\n", + CONFIG_SYSTEM_HEX2BIN_SWAP); + exit(exitcode); +} + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: + ****************************************************************************/ + +/**************************************************************************** + * Name: hex2bin_main + * + * Description: + * Main entry point when hex2bin is built as an NSH built-in task. + * + * Input Parameters: + * Standard task inputs + * + * Returned Value + * EXIT_SUCESS on success; EXIT_FAILURE on failure + * + ****************************************************************************/ + +int hex2bin_main(int argc, char **argv) +{ + struct lib_stdinstream_s stdinstream; + struct lib_stdsostream_s stdoutstream; + FAR const char *hexfile; + FAR const char *binfile; + FAR char *endptr; + FAR FILE *instream; + FAR FILE *outstream; + unsigned long baseaddr; + unsigned long endpaddr; + unsigned long swap; + int option; + int ret; + + /* Parse the command line options */ + + baseaddr = CONFIG_SYSTEM_HEX2BIN_BASEADDR; + endpaddr = CONFIG_SYSTEM_HEX2BIN_ENDPADDR; + swap = CONFIG_SYSTEM_HEX2BIN_SWAP; + + while ((option = getopt(argc, argv, ":hs:e:w:")) != ERROR) + { + switch (option) + { + case 'h': + show_usage(argv[0], EXIT_SUCCESS); + break; + + case 's': + baseaddr = strtoul(optarg, &endptr, 16); + if (endptr == optarg) + { + fprintf(stderr, "ERROR: Invalid argument to the -s option\n"); + show_usage(argv[0], EXIT_FAILURE); + } + break; + + case 'e': + endpaddr = strtoul(optarg, &endptr, 16); + if (endptr == optarg) + { + fprintf(stderr, "ERROR: Invalid argument to the -e option\n"); + show_usage(argv[0], EXIT_FAILURE); + } + break; + + case 'w': + swap = strtoul(optarg, &endptr, 16); + if (endptr == optarg || swap > (unsigned long)HEX2BIN_SWAP32) + { + fprintf(stderr, "ERROR: Invalid argument to the -w option\n"); + show_usage(argv[0], EXIT_FAILURE); + } + break; + + case ':': + fprintf(stderr, "ERROR: Missing required argument\n"); + show_usage(argv[0], EXIT_FAILURE); + break; + + default: + case '?': + fprintf(stderr, "ERROR: Unrecognized option\n"); + show_usage(argv[0], EXIT_FAILURE); + break; + } + } + + /* There should be two final parameters remaining on the command line */ + + if (optind >= argc) + { + printf("ERROR: Missing required <hexfile> and <binfile> arguments\n"); + show_usage(argv[0], EXIT_FAILURE); + } + + hexfile = argv[optind]; + optind++; + + if (optind >= argc) + { + printf("ERROR: Missing required <binfile> argument\n"); + show_usage(argv[0], EXIT_FAILURE); + } + + binfile = argv[optind]; + optind++; + + if (optind < argc) + { + printf("ERROR: Garbage at end of command line\n"); + show_usage(argv[0], EXIT_FAILURE); + } + + /* Open the HEX file for reading */ + + instream = fopen(hexfile, "r"); + if (instream == NULL) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + fprintf(stderr, "ERROR: Failed to open \"%s\" for reading: %d\n", + hexfile, errcode); + return -errcode; + } + + /* Open the BIN file for reading */ + + outstream = fopen(binfile, "wb"); + if (outstream == NULL) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + fprintf(stderr, "ERROR: Failed to open \"%s\" for writing: %d\n", + binfile, errcode); + fclose(instream); + return -errcode; + } + + /* Wrap the FILE streams as standard streams */ + + lib_stdinstream(&stdinstream, instream); + lib_stdsostream(&stdoutstream, outstream); + + /* And do the deed */ + + ret = hex2bin(&stdinstream.public, &stdoutstream.public, + (uint32_t)baseaddr, (uint32_t)endpaddr, + (enum hex2bin_swap_e)swap); + if (ret < 0) + { + fprintf(stderr, "ERROR: Failed to convert \"%s\" to binary: %d\n", + ret); + } + + /* Clean up and return */ + + fclose(instream); + fclose(outstream); + return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#endif /* CONFIG_SYSTEM_HEX2BIN_BUILTIN */ |