/*************************************************************************** * Copyright (C) 2005-2007 Nicolas Hadacek * * (C) 2003 by Alain Gibaud * * * * 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. * ***************************************************************************/ #include "hex_buffer.h" #include #include "devices/base/generic_device.h" //----------------------------------------------------------------------------- const char * const HexBuffer::FORMATS[Nb_Formats] = { "inhx8m", /*"inhx8s", */"inhx16", "inhx32" }; void HexBuffer::savePartial(TQTextStream &stream, Format format) const { BitValue oldseg; const_iterator block = begin(); int len; while ( fetchNextBlock(block, end(), &len) ) { // block found, write it BitValue seg = block.key() >> 15 ; // 2 * seg address if ( format==IHX32 && seg!=oldseg ) { char buf[50]; BitValue check = 0x02 + 0x04 + seg.byte(1) + seg.byte(0); sprintf(buf, ":02000004%04X%02X\n", seg.toUInt(), check.twoComplement().byte(0)); stream << buf; oldseg = seg; } writeHexBlock(stream, len, block, format); } } void HexBuffer::saveEnd(TQTextStream &stream) const { stream << ":00000001FF\n"; } /* Write one line of Intel-hex file * Original code source from Timo Rossi, * modified by Alain Gibaud to support large blocks write */ void HexBuffer::writeHexBlock(TQTextStream &stream, int reclen, // length (in words) const_iterator& data, // pointer to 1st data word (incremented by function) Format format) { while ( reclen>HEXBLKSIZE ) { writeHexBlock(stream, HEXBLKSIZE, data, format); reclen -= HEXBLKSIZE; } if ( reclen<=0 ) return; /* Oops, block has just a HEXBLKSIZE * n size */ char buf[20]; BitValue check = 0x0; // line start uint loc = data.key(); switch (format) { case IHX8M: case IHX32: loc *= 2; sprintf(buf, ":%02X%04X00", 2*reclen, loc & 0xFFFF); check += ((loc) & 0xff) + (((loc) >> 8) & 0xff) + 2*reclen; break; case IHX16: sprintf(buf, ":%02X%04X00", reclen, loc & 0xFFFF); check += (loc & 0xff) + ((loc >> 8) & 0xff) + reclen; break; case Nb_Formats: Q_ASSERT(false); break; } stream << buf; // data for (; reclen > 0; ++data, --reclen) { BitValue word = data.data(); switch (format) { case IHX8M: case IHX32: sprintf(buf, "%02X%02X", word.byte(0), word.byte(1)); break; case IHX16: sprintf(buf, "%02X%02X", word.byte(1), word.byte(0)); break; case Nb_Formats: Q_ASSERT(false); break; } stream << buf; check += word.byte(0) + word.byte(1); } // checksum, assumes 2-complement sprintf(buf, "%02X\n", check.twoComplement().byte(0)); stream << buf; } /* ------------------------------------------------------------------------- This routine detects the next block to output A block is a set of consecutive addresse words not containing 0xFFFFFFFF @return true if a block has been detected 'it' is updated to point to the first address of the block '*len' contains the size of the block */ bool HexBuffer::fetchNextBlock(const_iterator& it, const const_iterator &end, int *len) { uint startadr, curadr; // for( i = *start ; (i < MAXPICSIZE) && (Mem[i] == INVALID) ; ++i) ; // skip non-used words // Search block start while ( it!=end && !it.data().isInitialized() ) ++it; // if(i >= MAXPICSIZE ) return false ; if ( it==end ) return false; //for( *start = i ; (i < MAXPICSIZE) && (Mem[i] != INVALID) ; ++i) ; //*len = i - *start ; // search block end - a block may not cross a segment boundary const_iterator itt(it) ; for (curadr = startadr = itt.key(), ++itt; itt!=end; ++itt) { if ( itt.key()!=curadr+1 ) break; // non contiguous addresses if ( !itt.data().isInitialized() ) break; // unused word found if ( ((itt.key()) & 0xFFFF0000U)!=(curadr & 0xFFFF0000U) ) break; // cross segment boundary curadr = itt.key(); } *len = curadr - startadr + 1 ; return *len != 0 ; } TQString HexBuffer::ErrorData::message() const { switch (type) { case UnrecognizedFormat: return i18n("Unrecognized format (line %1).").tqarg(line); case UnexpectedEOF: return i18n("Unexpected end-of-file."); case UnexpectedEOL: return i18n("Unexpected end-of-line (line %1).").tqarg(line); case WrongCRC: return i18n("CRC mismatch (line %1).").tqarg(line); } Q_ASSERT(false); return TQString(); } bool HexBuffer::load(TQTextStream &stream, TQStringList &errors) { Format format; TQValueList list = load(stream, format); if ( list.isEmpty() ) return true; errors.clear(); for (uint i=0; i HexBuffer::load(TQTextStream &stream, Format &format) { clear(); format = Nb_Formats; TQValueList errors; load(stream, format, errors); if ( format==Nb_Formats ) format = IHX8M; // default return errors; } /* ------------------------------------------------------------------------- Read a Intel HEX file of either INHX16 or INHX8M format type, detecting the format automagicly by the wordcount and length of the line Tested in 8 and 16 bits modes ------------------------------------------------------------------------ */ void HexBuffer::load(TQTextStream &stream, Format &format, TQValueList &errors) { uint addrH = 0; // upper 16 bits of 32 bits address (inhx32 format) uint line = 1; for (; !stream.atEnd(); line++) { // read each line TQString s = stream.readLine(); if ( !s.startsWith(":") ) continue; // skip invalid intel hex line s = s.stripWhiteSpace(); // clean-up white spaces at end-of-line if ( s==":" ) continue; // skip empty line const char *p = s.latin1(); p += 1; // skip ':' uint bytecount = (s.length()-11) / 2; // number of data bytes of this record // get the byte count, the address and the type for this line. uint count, addr, type; if ( sscanf(p, "%02X%04X%02X", &count , &addr, &type)!=3 ) { errors += ErrorData(line, UnrecognizedFormat); return; } p += 8; uint cksum = count + (addr >> 8) + (addr & 0xFF) + type; if( type==0x01 ) { // EOF field :00 0000 01 FF uint data; if ( sscanf(p, "%02X", &data)!=1 ) errors += ErrorData(line, UnexpectedEOL); else if ( ((cksum+data) & 0xFF)!=0 ) errors += ErrorData(line, WrongCRC); return; } if ( type==0x04 ) { // linear extended record (for 0x21xxxx, :02 0000 04 0021 D9) if( sscanf(p, "%04X", &addrH)!=1 ) { errors += ErrorData(line, UnrecognizedFormat); // bad address record return; } p += 4; cksum += (addrH & 0xFF); cksum += (addrH >> 8); if ( format==Nb_Formats || format==IHX8M ) format = IHX32; else if ( format!=IHX32 ) { errors += ErrorData(line, UnrecognizedFormat); // inconsistent format return; } uint data; if ( sscanf(p, "%02X", &data)!=1 ) errors += ErrorData(line, UnexpectedEOL); else if ( ((cksum+data) & 0xFF)!=0 ) errors += ErrorData(line, WrongCRC); //qDebug("new address high: %s", toHex(addrH<<16, 8).data()); continue; // goto next record } /* Figure out if its INHX16 or INHX8M if count is a 16 bits words count => INHX16 if count is a byte count => INHX8M or INHX32 */ if ( bytecount==count ) { if ( format==Nb_Formats ) format = IHX8M; else if ( format!=IHX8M && format!=IHX32 ) { errors += ErrorData(line, UnrecognizedFormat); // inconsistent format return; } /* Processing a INHX8M line */ /* Modified to be able to read fuses from hexfile created by C18 toolchain */ /* changed by Tobias Schoene 9 April 2005, */ /* modified by A.G, because low and hi bytes was swapped in Tobias's code , 8 may 2005 */ uint addrbase = ((addrH << 16) | addr); //qDebug("line %i: address %s", line, toHex(addrbase, 8).data()); for (uint x = 0; x> 1; BitValue value = (*this)[a]; if ( addrbase+x & 1 ) insert(a, value.maskWith(0x00FF) | data << 8); // Odd addr => Hi byte else insert(a, value.maskWith(0xFF00) | data); // Low byte //if ( x==0 ) qDebug("fb@%s: %s", toHex(addrbase+x >> 1, 8).data(), toHex(fb[addrbase+x >> 1], 8).data()); cksum += data; } } else if ( bytecount==count*2 ) { if ( format==Nb_Formats ) format = IHX16; else if ( format!=IHX16 ) { errors += ErrorData(line, UnrecognizedFormat); // inconsistent format return; } /* Processing a INHX16 line */ for(uint x=0; x