//----------------------------------------------------------------------------- // // Cosmodog, Ltd. // 415 West Huron Street // Chicago, IL 60610 // http://www.cosmodog.com // // Maintained at // http://home.pacbell.net/theposts/picmicro // //----------------------------------------------------------------------------- // // Copyright (C) 1999-2002 Cosmodog, Ltd. // Copyright (c) 2004 Jeffery L. Post // // Please send bug reports for version 0.6.0 or higher to // j_post pacbell net. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // //----------------------------------------------------------------------------- // // This module reads the input file, autodetects the file type, and returns // bytes as requested. Valid file formats are Intel Hex and Motorola // S-record. Intel Hex is identified by a leading : on each line; Motorola S // is identified by a leading S on each line. Anything else is an error. // // Call InitParse() once to initialize, then call GetNextByte() to get each // character. GetNextByte() will return false when out of characters. // //----------------------------------------------------------------------------- // // INTEL HEX: // :nnaaaarrdddddd...cc // where // nn - number of data bytes // aaaa - address // rr - record type (0 = data record, 1 = end record, 2 = segment address, 4 = extended address) // dd - data bytes // cc - checksum (0 minus the sum of all other bytes excluding the colon) // // example: // data record: // :1000A0006707610AAE02EE046707610A0D028E005F // // number of data bytes: 0x10 (16) // address: 0x00A0 // record type: 0x00 (data record) // data: 0x67 0x07 0x61 0x0A 0xAE 0x02 0xEE 0x04 0x67 0x07 0x61 0x0A 0x0D 0x02 0x8E 0x00 // checksum: 0x5f // // end record: // :00000001FF // // number of data bytes: 0x00 // address: 0x0000 (unused) // record type: 0x01 (end record) // data: none // checksum: 0xff // // the checksum is set such that the sum of all bytes (excluding the colon) equals zero // the end record is treated as end of segment, and does not terminate processing // //----------------------------------------------------------------------------- // // MOTOROLA S: // Sxnnaaaadddddd...cc // where: // Sx - the record type // nn - the number of data bytes // aaaa - address (aaaa for S1, aaaaaa for S2, aaaaaa for S3) // dd - data bytes // cc - checksum // // S0: comment record // S1: data record with 16 bit address // S2: data record with 24 bit address // S3: data record with 32 bit address // S7: end of file record? // S9: end of file record // //----------------------------------------------------------------------------- #ifdef WIN32 #include #define bool int #define true TRUE #define false FALSE #endif #include #include #include "parse.h" #define INTEL_CHAR ':' #define MOT_CHAR 'S' #define COMMENT_CHAR ';' #define SPACE_CHAR ' ' #define NEWLINE_CHAR '\n' #define NULL_CHAR 0 #define DATARECORD 0 // data record #define ENDRECORD 1 // end record #define SEGADDRESS 2 // segment address record (INHX32) #define EXTADDRESS 4 // extended linear address record (INHX32) #define MAX_LINE_LEN 256 static char lineBuffer[MAX_LINE_LEN]; // place to read records from the input file static int byteCount; // number of bytes read in and ready to be returned static int byteIdx; // index to the next byte to be read static unsigned int byteAddress; // address of the next byte to be read static unsigned int extendedLinearAddress; // bits 31-16 are bits 31-16 of the address for intel hex records, bits 15-0 are 0 //----------------------------------------------------------------------------- // convert two ascii hex characters to an 8-bit unsigned int // return zero if out of range (not ascii hex) static unsigned char atoh(char high, char low) { char hi, lo; int value; hi = toupper(high); lo = toupper(low); value = 0; if (hi >= '0' && hi <= '9') value += ((hi - '0') << 4); else if (hi >= 'A' && hi <= 'F') value += ((hi - 'A' + 0x0a) << 4); if (lo >= '0' && lo <= '9') value += (lo - '0'); else if (lo >= 'A' && lo <= 'F') value += (lo - 'A' + 0x0a); return(value); } //----------------------------------------------------------------------------- // read a line from the given file into the array line // if there is a read error, return false // lineLength is considered to be the maximum number of characters // to read into the line (including the 0 terminator) // if the line fills before a CR is hit, overFlow will be set true, and the rest of the // line will be read, but not stored // if the EOF is hit, atEOF is set true static bool GetLine(FILE *theFile, char *line, int lineLength, bool *atEOF, bool *overFlow) { int i; unsigned char c; unsigned int numRead; bool stopReading, hadError; i = 0; // index into output line stopReading = hadError = (*atEOF) = (*overFlow)= false; while (!stopReading) { numRead = fread(&c, 1, 1, theFile); // get character from input if (numRead) // if something was read, check it, and add to output line { if (c == '\n' || c== '\0') // found termination? stopReading = true; // yes, output line is complete else { if (c != '\n' && c != '\r') // see if the character should be added to the line { if (i < lineLength - 1) // make sure there is room to store it line[i++] = c; // store it if there is room else (*overFlow) = true; // complain of overflow, but continue to the end } } } else { stopReading = true; if (feof(theFile)) (*atEOF) = true; // tell caller that EOF was encountered else hadError = true; } } if (lineLength) line[i] = '\0'; // terminate the line if possible return(!hadError); // return error status } //----------------------------------------------------------------------------- // set up to interpret the line as an intel hex record static bool GetIntelRecord(FILE *theFile) { bool done; int i, len, type, chksum; done = false; type = atoh(lineBuffer[7], lineBuffer[8]); switch (type) { case DATARECORD: // don't know how to cope with anything but 16-bit addresses for now byteIdx = 9; // the ninth character is the high nibble of the first data byte byteCount = atoh(lineBuffer[1], lineBuffer[2]); byteAddress = atoh(lineBuffer[3], lineBuffer[4]) * 256 + atoh(lineBuffer[5], lineBuffer[6]) + extendedLinearAddress; break; case ENDRECORD: break; case SEGADDRESS: extendedLinearAddress = (atoh(lineBuffer[9], lineBuffer[10]) * 256 + atoh(lineBuffer[11], lineBuffer[12])) << 4; break; case EXTADDRESS: extendedLinearAddress = (atoh(lineBuffer[9], lineBuffer[10]) * 256 + atoh(lineBuffer[11], lineBuffer[12])) << 16; break; default: fprintf(stderr, "GetIntelRecord: Unknown code %d: %s\n", type, lineBuffer); done = true; break; } len = atoh(lineBuffer[1], lineBuffer[2]) * 2; len += 8; // add count, address, and type overhead chksum = 0; for (i=0; i