FreeCalypso > hg > fc-usbser-tools
diff cp2102/intel_hex_in.c @ 55:c0084bf153e5
cp2102: Intel HEX reading implemented
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 11 Sep 2023 19:45:56 +0000 |
parents | |
children | 842cff427588 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp2102/intel_hex_in.c Mon Sep 11 19:45:56 2023 +0000 @@ -0,0 +1,148 @@ +/* + * This module implements a function for reading CP2102 EEPROM images + * in the Intel HEX format which we've copied from cp210x-program-1.0, + * the Python-language tool from 2014. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <stdlib.h> +#include "cp210x_defs.h" + +extern u_char eeprom[SIZE_EEPROM]; + +static int +decode_hex_digit(c) +{ + if (c >= '0' && c <= '9') + return(c - '0'); + if (c >= 'A' && c <= 'F') + return(c - 'A' + 10); + if (c >= 'a' && c <= 'f') + return(c - 'a' + 10); + return(-1); +} + +static int +decode_hex_byte(str) + char *str; +{ + int u, l; + + u = decode_hex_digit(str[0]); + l = decode_hex_digit(str[1]); + return (u << 4) | l; +} + +void +read_intel_hex(filename) + char *filename; +{ + FILE *inf; + char linebuf[1024], *cp; + int lineno; + unsigned eeprom_offset; + unsigned payload_len, record_len, n; + u_char record[21], csum; + unsigned record_addr, expect_addr; + + inf = fopen(filename, "r"); + if (!inf) { + perror(filename); + exit(1); + } + eeprom_offset = 0; + for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) { + if (!index(linebuf, '\n')) { + fprintf(stderr, + "%s line %d: too long or missing newline\n", + filename, lineno); + exit(1); + } + if (linebuf[0] != ':') + continue; + if (!isxdigit(linebuf[1]) || !isxdigit(linebuf[2])) { +inv_record: fprintf(stderr, + "%s line %d: invalid Intex HEX record\n", + filename, lineno); + exit(1); + } + payload_len = decode_hex_byte(linebuf + 1); + if (payload_len > 16) { +bad_payload_len: fprintf(stderr, + "%s line %d: unsupported payload length\n", + filename, lineno); + exit(1); + } + record_len = payload_len + 5; + cp = linebuf + 1; + csum = 0; + for (n = 0; n < payload_len; n++) { + if (!isxdigit(cp[0]) || !isxdigit(cp[1])) + goto inv_record; + record[n] = decode_hex_byte(cp); + cp += 2; + csum += record[n]; + } + if (csum) { + fprintf(stderr, + "%s line %d: bad Intel HEX record checksum\n", + filename, lineno); + exit(1); + } + if (record[3] == 0x00) { + if (payload_len != 16) + goto bad_payload_len; + if (eeprom_offset >= SIZE_EEPROM) { + fprintf(stderr, + "%s line %d: data continues past valid EEPROM size\n", + filename, lineno); + exit(1); + } + record_addr = (record[1] << 8) | record[2]; + expect_addr = EEPROM_START_ADDR + eeprom_offset; + if (record_addr != expect_addr) { + fprintf(stderr, + "%s line %d: record addr is %04X, but we expect %04X\n", + filename, lineno, record_addr, + expect_addr); + exit(1); + } + bcopy(record + 4, eeprom + eeprom_offset, 16); + eeprom_offset += 16; + } else if (record[3] == 0x01) { + if (payload_len) { + fprintf(stderr, + "%s line %d: nonzero payload length in end-marker record\n", + filename, lineno); + exit(1); + } + if (eeprom_offset < SIZE_EEPROM) { + fprintf(stderr, + "%s line %d: end-marker without full data\n", + filename, lineno); + exit(1); + } + break; + } else { + fprintf(stderr, + "%s line %d: unsupported Intel HEX record type\n", + filename, lineno); + exit(1); + } + } + fclose(inf); + if (!eeprom_offset) { + fprintf(stderr, "error: no Intel HEX EEPROM data found in %s\n", + filename); + exit(1); + } + if (eeprom_offset < SIZE_EEPROM) { + fprintf(stderr, "error: %s contains truncated data\n", + filename); + exit(1); + } +}