/* Read ".HEX" (Intel-Hex) files and store it in memory
Copyright 2001-2005 Craig Franklin
*/
#include "stdhdr.h"
#include "libgputils.h"
// used in INHX8 INHX16 INHX32
#define IHEX_RECTYPE_DATA 0// yes yes yes
#define IHEX_RECTYPE_EOF 1// yes yes yes
#define IHEX_RECTYPE_EXT_SEG_ADDR 2// no yes no
#define IHEX_RECTYPE_START_SEG_ADDR 3// no yes no
#define IHEX_RECTYPE_EXT_LIN_ADDR 4// no no yes
#define IHEX_RECTYPE_START_LIN_ADDR 5// no no yes
// address bits 16 20 32
struct Hexdata:public hex_data{
uint8_t checksum;
FILE* infile;
char* linept;
char linebuf[520]; // large structures at end -> shorter code
uint8_t _readbyte();
uint16_t _readword();
Hexdata(const char*,MemBlock_t*);
};
/*------------------------------------------------------------------------------------------------*/
/* Converts a single ASCII character into a number. */
static uint8_t _a2n(uint8_t Character) {
uint8_t number;
if (Character <= '9') {
number = Character - '0';
}
else {
/* Convert lower case to upper. */
Character &= ~('a' - 'A');
number = Character - ('A' - 10);
}
return number;
}
/*------------------------------------------------------------------------------------------------*/
uint8_t Hexdata::_readbyte() {
uint8_t number;
linept++;
number = (uint8_t)(_a2n((uint8_t)(*linept)) << 4);
linept++;
number |= _a2n((uint8_t)(*linept));
checksum += number;
return number;
}
/*------------------------------------------------------------------------------------------------*/
uint16_t Hexdata::_readword() {
uint16_t number;
number = (uint16_t)_readbyte();
number |= (uint16_t)_readbyte() << 8;
return number;
}
/*------------------------------------------------------------------------------------------------*/
static uint16_t _swapword(uint16_t Input) {
uint16_t number;
number = (uint16_t)((Input & 0xFF) << 8) | (uint16_t)((Input & 0xFF00) >> 8);
return number;
}
/*------------------------------------------------------------------------------------------------*/
Hexdata::Hexdata(const char* File_name, MemBlock_t* M) {
/* Open the input file. */
infile = fopen(File_name, "rt");
if (!infile) {
perror(File_name);
exit(1);
}
/* Go to the beginning of the file. */
fseek(infile, 0L, SEEK_SET);
/* Set the line pointer to the beginning of the line buffer. */
unsigned page = 0;
/* Read a line of data from the file, if NULL stop. */
while (fgets(linebuf, sizeof linebuf, infile)) {
/* Set the line pointer to the beginning of the line buffer. */
linept = linebuf;
checksum = 0;
/* Fetch the number of bytes. */
unsigned length = _readbyte();
if (!length) fclose(infile);
/* Fetch the address. */
unsigned address = _swapword(_readword());
if (hex_format == INHX16) {
address *= 2;
length *= 2;
}
/* Read the type of record. */
unsigned type = _readbyte();
if (type == IHEX_RECTYPE_EXT_LIN_ADDR) {
if (hex_format == INHX16) {
printf("\nHex Format Error\n");
fclose(infile);
error = true;
}
/* INHX32 segment line. */
page = (unsigned)((_readbyte() << 8) + _readbyte()) << 16;
hex_format = INHX32;
}else{
/* Read the data (skipping last byte if at odd address). */
for (unsigned i = 0; i < length; ++i) {
uint8_t byte = _readbyte();
if (hex_format == INHX16) {
gp_mem_b_put(M, page | ((address + i) ^ 1), byte, File_name, NULL);
}
else {
gp_mem_b_put(M, page | (address + i), byte, File_name, NULL);
}
}
size += length;
}
/* Read the checksum, data is thrown away. */
_readbyte();
if (checksum) {
if (hex_format == INHX8M) {
/* First attempt at INHX8M failed, try INHX16. */
fseek(infile, 0L, SEEK_SET);
hex_format = INHX16;
size = 0;
/* Data in i_memory is trash. */
gp_mem_i_free(M);
M = gp_mem_i_create();
}else{
printf("\nChecksum Error\n");
fclose(infile);
error = true;
}
}
/* Set the line pointer to the beginning of the line buffer. */
linept = linebuf;
}
fclose(infile);
}
FUNC(hex_data_t*) gp_readhex(const char* File_name, MemBlock_t* M) {
return new Hexdata(File_name,M);
}
Detected encoding: ASCII (7 bit) | 2
|