Added AVROSP application for using the bootloader.

This commit is contained in:
skarg
2009-05-27 19:10:13 +00:00
parent f96e8b6118
commit 911d841496
25 changed files with 5700 additions and 0 deletions
@@ -0,0 +1,976 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRBootloader.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing an interface to the AVR bootloader
* described in Application Note AVR109.
* This class is derived from AVRPRogrammer.
*
*
****************************************************************************/
#include "AVRBootloader.hpp"
#include <sstream>
#include <iomanip>
#define MEM_PROGRESS_GRANULARITY 256 // For use with progress indicator.
/* Constructor */
AVRBootloader::AVRBootloader( CommChannel * _comm ) :
AVRProgrammer::AVRProgrammer( _comm )
{
/* No code here */
}
/* Destructor */
AVRBootloader::~AVRBootloader()
{
/* No code here */
}
bool AVRBootloader::enterProgrammingMode()
{
return true; // Always OK for bootloader.
}
bool AVRBootloader::leaveProgrammingMode()
{
return true; // Always OK for bootloader.
}
bool AVRBootloader::chipErase()
{
/* Send command 'e' */
comm->sendByte( 'e' );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Chip erase failed! "
"Programmer did not return CR after 'e'-command." );
return true; // Indicate supported command.
}
bool AVRBootloader::readOSCCAL( long pos, long * value )
{
return false; // Indicate unsupported command.
}
bool AVRBootloader::readSignature( long * sig0, long * sig1, long * sig2 )
{
/* Send command 's' */
comm->sendByte( 's' );
comm->flushTX();
/* Get actual signature */
*sig2 = comm->getByte();
*sig1 = comm->getByte();
*sig0 = comm->getByte();
}
bool AVRBootloader::checkSignature( long sig0, long sig1, long sig2 )
{
long sig[3];
/* Get signature */
readSignature( sig, sig+1, sig+2 );
/* Compare signature */
if( sig[0] != sig0 || sig[1] != sig1 || sig[2] != sig2 )
{
ostringstream msg;
msg << "Signature does not match selected device! ";
msg << "Actual signature: (" << hex
<< "0x" << setw(2) << sig[0] << " "
<< "0x" << setw(2) << sig[1] << " "
<< "0x" << setw(2) << sig[2] << ") "
<< "Signature from XML-file: (" << hex
<< "0x" << setw(2) << sig0 << " "
<< "0x" << setw(2) << sig1 << " "
<< "0x" << setw(2) << sig2 << ").";
throw new ErrorMsg( msg.str() );
}
return true; // Indicate supported command.
}
bool AVRBootloader::writeFlashByte( long address, long value )
{
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Move data if at odd address */
if( address & 0x01 ) // Odd address?
value = (value << 8) | 0x00ff; // Move to high byte of one flash word.
else
value |= 0xff00; // Ensure no-write for high byte.
/* Send low and high byte */
writeFlashLowByte( value & 0xff );
writeFlashHighByte( value >> 8 );
/* Issue page write */
setAddress( address >> 1 ); // The address could be autoincremented.
writeFlashPage();
return true; // Indicate supported command.
}
bool AVRBootloader::writeEEPROMByte( long address, long value )
{
if( address >= 0x10000 )
throw new ErrorMsg( "EEPROM addresses above 64k are currently not supported!" );
setAddress( address );
/* Send data */
comm->sendByte( 'D' );
comm->sendByte( value );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing byte to EEPROM failed! "
"Programmer did not return CR after 'D'-command." );
return true; // Indicate supported command.
}
bool AVRBootloader::writeFlash( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Check that pagesize is set */
if( pagesize == -1 )
throw new ErrorMsg( "Programmer pagesize is not set!" );
/* Check block write support */
comm->sendByte( 'b' );
comm->flushTX();
if( comm->getByte() == 'Y' )
{
Util.log( "Using block mode...\r\n" );
return writeFlashBlock( data ); // Finished writing.
}
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start >> 1 ); // Flash operations use word addresses.
/* Need to write one odd byte first? */
address = start;
if( address & 1 )
{
/* Use only high byte */
writeFlashLowByte( 0xff ); // No-write in low byte.
writeFlashHighByte( data->getData( address ) );
address++;
/* Need to write page? */
if( (address % pagesize) == 0 ||
address > end ) // Just passed page limit or no more bytes to write?
{
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
setAddress( address >> 1 );
}
}
/* Write words */
while( (end-address+1) >= 2 ) // More words left?
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address >> 1 );
/* Write words */
writeFlashLowByte( data->getData( address ) );
writeFlashHighByte( data->getData( address+1 ) );
address += 2;
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
/* Need to write page? */
if( (address % pagesize) == 0 ||
address > end ) // Just passed a page limit or no more bytes to write?
{
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
setAddress( address >> 1 );
}
}
/* Need to write one even byte before finished? */
if( address == end )
{
/* Use only low byte */
writeFlashLowByte( data->getData( address ) );
writeFlashHighByte( 0xff ); // No-write in high byte.
address+=2;
/* Write page */
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::writeFlashBlock( HEXFile * data )
{
long start, end; // Data address range.
long blocksize; // Bootloader block size.
long bytecount;
long address;
/* Get block size, assuming command 'b' just issued and 'Y' has been read */
blocksize = (comm->getByte() << 8) | comm->getByte();
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Need to write one odd byte first? */
address = start;
if( address & 1 )
{
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Use only high byte */
writeFlashLowByte( 0xff ); // No-write in low byte.
writeFlashHighByte( data->getData( address ) );
address++;
/* Need to write page? */
if( (address % pagesize) == 0 ||
address > end ) // Just passed page limit or no more bytes to write?
{
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
setAddress( address >> 1 );
}
}
/* Need to write from middle to end of block first? */
if( (address % blocksize) > 0 ) // In the middle of a block?
{
bytecount = blocksize - (address % blocksize); // Bytes left in block.
if( (address+bytecount-1) > end ) // Is that past the write range?
{
bytecount = end-address+1; // Bytes left in write range.
bytecount &= ~0x01; // Adjust to word count.
}
if( bytecount > 0 )
{
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block write */
comm->sendByte( 'B' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
comm->sendByte( data->getData( address ) );
address++;
bytecount--;
}
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash block failed! "
"Programmer did not return CR after 'BxxF'-command." );
Util.progress( "#" ); // Advance progress indicator.
}
}
/* More complete blocks to write? */
while( (end-address+1) >= blocksize )
{
bytecount = blocksize;
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block write */
comm->sendByte( 'B' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
comm->sendByte( data->getData( address ) );
address++;
bytecount--;
}
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash block failed! "
"Programmer did not return CR after 'BxxF'-command." );
Util.progress( "#" ); // Advance progress indicator.
}
/* Any bytes left in last block */
if( (end-address+1) >= 1 )
{
bytecount = (end-address+1); // Get bytes left to write.
if( bytecount & 1 )
bytecount++; // Align to next word boundary.
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block write */
comm->sendByte( 'B' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
if( address > end )
comm->sendByte( 0xff ); // Don't write outside write range.
else
comm->sendByte( data->getData( address ) );
address++;
bytecount--;
}
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash block failed! "
"Programmer did not return CR after 'BxxF'-command." );
Util.progress( "#" ); // Advance progress indicator.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::readFlash( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
if( pagesize == -1 )
throw new ErrorMsg( "Programmer pagesize is not set!" );
/* Check block read support */
comm->sendByte( 'b' );
comm->flushTX();
if( comm->getByte() == 'Y' )
{
Util.log( "Using block mode...\r\n" );
return readFlashBlock( data ); // Finished writing.
}
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start >> 1 ); // Flash operations use word addresses.
/* Need to read one odd byte first? */
address = start;
if( address & 1 )
{
/* Read both, but use only high byte */
comm->sendByte( 'R' );
comm->flushTX();
data->setData( address, comm->getByte() ); // High byte.
comm->getByte(); // Dont use low byte.
address++;
}
/* Get words */
while( (end-address+1) >= 2 )
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address >> 1 );
/* Get words */
comm->sendByte( 'R' );
comm->flushTX();
data->setData( address+1, comm->getByte() ); // High byte.
data->setData( address, comm->getByte() ); // Low byte.
address += 2;
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
};
/* Need to read one even byte before finished? */
if( address == end )
{
/* Read both, but use only low byte */
comm->sendByte( 'R' );
comm->flushTX();
comm->getByte(); // Dont use high byte.
data->setData( address, comm->getByte() ); // Low byte.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::readFlashBlock( HEXFile * data )
{
long start, end; // Data address range.
long blocksize; // Bootloader block size.
long bytecount;
long address;
/* Get block size, assuming command 'b' just issued and 'Y' has been read */
blocksize = (comm->getByte() << 8) | comm->getByte();
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Need to read one odd byte first? */
address = start;
if( address & 1 )
{
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Use only high word */
comm->sendByte( 'R' );
comm->flushTX();
data->setData( address, comm->getByte() ); // High byte.
comm->getByte(); // Low byte.
address++;
}
/* Need to read from middle to end of block first? */
if( (address % blocksize) > 0 ) // In the middle of a block?
{
bytecount = blocksize - (address % blocksize); // Bytes left in block.
if( (address+bytecount-1) > end ) // Is that past the read range?
{
bytecount = end-address+1; // Bytes left in read range.
bytecount &= ~0x01; // Adjust to word count.
}
if( bytecount > 0 )
{
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block read */
comm->sendByte( 'g' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
data->setData( address, comm->getByte() );
address++;
bytecount--;
}
Util.progress( "#" ); // Advance progress indicator.
}
}
/* More complete blocks to read? */
while( (end-address+1) >= blocksize )
{
bytecount = blocksize;
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block read */
comm->sendByte( 'g' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
data->setData( address, comm->getByte() );
address++;
bytecount--;
}
Util.progress( "#" ); // Advance progress indicator.
}
/* Any bytes left in last block */
if( (end-address+1) >= 1 )
{
bytecount = (end-address+1); // Get bytes left to read.
if( bytecount & 1 )
bytecount++; // Align to next word boundary.
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block read */
comm->sendByte( 'g' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
if( address > end )
comm->getByte(); // Don't read outside write range.
else
data->setData( address, comm->getByte() );
address++;
bytecount--;
}
Util.progress( "#" ); // Advance progress indicator.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::writeEEPROM( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Check block write support */
comm->sendByte( 'b' );
comm->flushTX();
if( comm->getByte() == 'Y' )
{
Util.log( "Using block mode...\r\n" );
return writeEEPROMBlock( data ); // Finished writing.
}
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start );
/* Send data */
address = start;
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address );
/* Send byte */
comm->sendByte( 'D' );
comm->sendByte( data->getData( address ) );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing byte to EEPROM failed! "
"Programmer did not return CR after 'D'-command." );
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
address++;
} while( address <= end );
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::writeEEPROMBlock( HEXFile * data )
{
long start, end; // Data address range.
long blocksize; // Bootloader block size.
long bytecount;
long address;
/* Get block size, assuming command 'b' just issued and 'Y' has been read */
blocksize = (comm->getByte() << 8) | comm->getByte();
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Send data */
address = start;
while( address <= end ) // More bytes to write?
{
bytecount = blocksize; // Try a full block.
if( (address+bytecount-1) > end ) // Is that past the write range?
{
bytecount = end-address+1; // Bytes left in write range.
}
setAddress( address );
/* Start EEPROM block write */
comm->sendByte( 'B' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'E' ); // EEPROM memory.
while( bytecount > 0 )
{
comm->sendByte( data->getData( address ) );
comm->flushTX();
address++;
bytecount--;
}
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing EEPROM block failed! "
"Programmer did not return CR after 'BxxE'-command." );
Util.progress( "#" ); // Advance progress indicator.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::readEEPROM( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Check block write support */
comm->sendByte( 'b' );
comm->flushTX();
if( comm->getByte() == 'Y' )
{
Util.log( "Using block mode...\r\n" );
return readEEPROMBlock( data ); // Finished writing.
}
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start );
/* Read data */
address = start;
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address );
/* Get byte */
comm->sendByte( 'd' );
comm->flushTX();
data->setData( address, comm->getByte() );
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
address++;
} while( address <= end );
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::readEEPROMBlock( HEXFile * data )
{
long start, end; // Data address range.
long blocksize; // Bootloader block size.
long bytecount;
long address;
/* Get block size, assuming command 'b' just issued and 'Y' has been read */
blocksize = (comm->getByte() << 8) | comm->getByte();
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Read data */
address = start;
while( address <= end ) // More bytes to read?
{
bytecount = blocksize; // Try a full block.
if( (address+bytecount-1) > end ) // Is that past the read range?
{
bytecount = end-address+1; // Bytes left in read range.
}
setAddress( address );
/* Start EEPROM block read */
comm->sendByte( 'g' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'E' ); // EEPROM memory.
while( bytecount > 0 )
{
data->setData( address, comm->getByte() );
address++;
bytecount--;
}
Util.progress( "#" ); // Advance progress indicator.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::writeLockBits( long bits )
{
/* Send command 'l' */
comm->sendByte( 'l' );
comm->sendByte( bits & 0xff );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing lock bits failed! "
"Programmer did not return CR after 'l'-command." );
return true; // Indicate supported command.
}
bool AVRBootloader::readLockBits( long * bits )
{
/* Send command 'r' */
comm->sendByte( 'r' );
comm->flushTX();
/* Get data */
*bits = comm->getByte();
return true; // Indicate supported command.
}
bool AVRBootloader::writeFuseBits( long bits )
{
return false; // Indicate unsupported command.
}
bool AVRBootloader::readFuseBits( long * bits )
{
long lowfuse, highfuse;
/* Send command 'N' */
comm->sendByte( 'N' );
comm->flushTX();
/* Get high fuse bits */
highfuse = comm->getByte();
/* Send command 'F' */
comm->sendByte( 'F' );
comm->flushTX();
/* Get low fuse bits */
lowfuse = comm->getByte();
*bits = (highfuse << 8) | lowfuse;
return true; // Indicate supported command.
}
bool AVRBootloader::writeExtendedFuseBits( long bits )
{
return false; // Indicate unsupported command.
}
bool AVRBootloader::readExtendedFuseBits( long * bits )
{
/* Send command 'Q' */
comm->sendByte( 'Q' );
comm->flushTX();
/* Get data */
*bits = comm->getByte();
return true; // Indicate supported command.
}
bool AVRBootloader::programmerSoftwareVersion( long * major, long * minor )
{
/* Send command 'V' to get software version */
comm->sendByte( 'V' );
comm->flushTX();
/* Get data */
*major = comm->getByte();
*minor = comm->getByte();
return true; // Indicate supported command.
}
bool AVRBootloader::programmerHardwareVersion( long * major, long * minor )
{
return false; // Indicate unsupported command.
}
void AVRBootloader::setAddress( long address )
{
/* Set current address */
if( address < 0x10000 ) {
comm->sendByte( 'A' );
comm->sendByte( (address >> 8) & 0xff );
comm->sendByte( address & 0xff );
comm->flushTX();
} else {
comm->sendByte( 'H' );
comm->sendByte( (address >> 16) & 0xff );
comm->sendByte( (address >> 8) & 0xff );
comm->sendByte( address & 0xff );
comm->flushTX();
}
/* Should return CR */
if( comm->getByte() != '\r' ) {
throw new ErrorMsg( "Setting address for programming operations failed! "
"Programmer did not return CR after 'A'-command." );
}
}
void AVRBootloader::writeFlashLowByte( long value )
{
comm->sendByte( 'c' );
comm->sendByte( value );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash low byte failed! "
"Programmer did not return CR after 'c'-command." );
}
void AVRBootloader::writeFlashHighByte( long value )
{
comm->sendByte( 'C' );
comm->sendByte( value );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash high byte failed! "
"Programmer did not return CR after 'C'-command." );
}
void AVRBootloader::writeFlashPage()
{
comm->sendByte( 'm' );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash page failed! "
"Programmer did not return CR after 'm'-command." );
}
/* end of file */
@@ -0,0 +1,84 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRBootloader.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing an interface to the AVR bootloader
* described in Application Note AVR109.
* This class is derived from AVRPRogrammer.
*
*
****************************************************************************/
#ifndef AVRBOOTLOADER_HPP
#define AVRBOOTLOADER_HPP
using namespace std;
#include "AVRProgrammer.hpp"
#include "Utility.hpp"
class AVRBootloader : public AVRProgrammer
{
protected:
virtual void setAddress( long address );
virtual void writeFlashLowByte( long value ); // Alwyas low byte first...
virtual void writeFlashHighByte( long value ); // ...then high byte.
virtual void writeFlashPage();
virtual bool writeFlashBlock( HEXFile * data );
virtual bool readFlashBlock( HEXFile * data );
virtual bool writeEEPROMBlock( HEXFile * data );
virtual bool readEEPROMBlock( HEXFile * data );
public:
/* Constructor */
AVRBootloader( CommChannel * _comm );
/* Destructor */
~AVRBootloader();
/* Methods */
virtual bool enterProgrammingMode();
virtual bool leaveProgrammingMode();
virtual bool chipErase();
virtual bool readOSCCAL( long pos, long * value );
virtual bool readSignature( long * sig0, long * sig1, long * sig2 );
virtual bool checkSignature( long sig0, long sig1, long sig2 );
virtual bool writeFlashByte( long address, long value );
virtual bool writeEEPROMByte( long address, long value );
virtual bool writeFlash( HEXFile * data );
virtual bool readFlash( HEXFile * data );
virtual bool writeEEPROM( HEXFile * data );
virtual bool readEEPROM( HEXFile * data );
virtual bool writeLockBits( long bits );
virtual bool readLockBits( long * bits );
virtual bool writeFuseBits( long bits );
virtual bool readFuseBits( long * bits );
virtual bool writeExtendedFuseBits( long bits );
virtual bool readExtendedFuseBits( long * bits );
virtual bool programmerSoftwareVersion( long * major, long * minor );
virtual bool programmerHardwareVersion( long * major, long * minor );
};
#endif
@@ -0,0 +1,157 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRDevice.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 4017 $
* Date : $Date: 2008-06-02 14:26:03 +0200 (ma, 02 jun 2008) $
* Updated by : $Author: khole $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class containing information of device memory sizes etc.
* It also provides funcitons for reading these parameters from
* the PartDescriptionFiles supplied with AVR Studio 4.
*
*
****************************************************************************/
#include "AVRDevice.hpp"
/* Constructor */
AVRDevice::AVRDevice( const string & _deviceName ) :
deviceName( _deviceName )
{
flashSize =
eepromSize = 0;
hasFuseBits = false;
hasExtendedFuseBits = false;
signature0 =
signature1 =
signature2 = 0;
pagesize = -1;
}
/* Destructor */
AVRDevice::~AVRDevice()
{
/* no code here */
}
/* Read parameters from AVR Studio XML files */
void AVRDevice::readParametersFromAVRStudio( vector<string> & searchpath )
{
string path;
string signature;
string cache;
#ifndef NOREGISTRY
/* Locate the directory containing the XML files from the Windows registry database */
try
{
path = Util.getRegistryValue( "SOFTWARE\\Atmel\\AVRTools\\", "AVRToolsPath" );
path += "\\PartDescriptionFiles";
searchpath.push_back( path );
} catch( ErrorMsg * e )
{
delete e;
}
#endif
/* Search for file */
path.erase();
int i;
for( i = 0; i < searchpath.size(); i++ )
{
path = searchpath[i] + "\\" + deviceName + ".xml";
if( Util.fileExists( path ) )
break;
}
if( i == searchpath.size() )
throw new ErrorMsg( "Device XML file not found in search path!" );
/* Parse the file for required info */
Util.log( "Parsing '" + path + "'...\r\n" );
XMLFile f( path ); // Load XML info
flashSize = atoi( f.getValue( "AVRPART\\MEMORY\\PROG_FLASH" ).c_str() );
eepromSize = atoi( f.getValue( "AVRPART\\MEMORY\\EEPROM" ).c_str() );
cache += "<AVRPART><MEMORY><PROG_FLASH>";
cache += f.getValue( "AVRPART\\MEMORY\\PROG_FLASH" );
cache += "</PROG_FLASH><EEPROM>";
cache += f.getValue( "AVRPART\\MEMORY\\EEPROM" );
cache += "</EEPROM>";
if( f.exists( "AVRPART\\MEMORY\\BOOT_CONFIG" ) )
{
pagesize = atoi( f.getValue( "AVRPART\\MEMORY\\BOOT_CONFIG\\PAGESIZE" ).c_str() );
pagesize <<= 1; // We want pagesize in bytes.
cache += "<BOOT_CONFIG><PAGESIZE>";
cache += f.getValue( "AVRPART\\MEMORY\\BOOT_CONFIG\\PAGESIZE" );
cache += "</PAGESIZE></BOOT_CONFIG>";
}
cache += "</MEMORY>";
if( f.exists( "AVRPART\\FUSE" ) )
{
hasFuseBits = true;
cache += "<FUSE>";
if( f.exists( "AVRPART\\FUSE\\EXTENDED" ) )
{
hasExtendedFuseBits = true;
cache += "<EXTENDED></EXTENDED>";
}
cache += "</FUSE>";
}
signature = f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR000" );
signature.erase( 0, 1 ); // Remove the $ character.
signature0 = Util.convertHex( signature );
signature = f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR001" );
signature.erase( 0, 1 ); // Remove the $ character.
signature1 = Util.convertHex( signature );
signature = f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR002" );
signature.erase( 0, 1 ); // Remove the $ character.
signature2 = Util.convertHex( signature );
cache += "<ADMIN><SIGNATURE><ADDR000>";
cache += f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR000" );
cache += "</ADDR000><ADDR001>";
cache += f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR001" );
cache += "</ADDR001><ADDR002>";
cache += f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR002" );
cache += "</ADDR002></SIGNATURE></ADMIN></AVRPART>\r\n";
/* Save cached file to application directory */
Util.log( "Saving cached XML parameters...\r\n" );
Util.saveString( cache, searchpath[1] + "\\" + deviceName + ".xml" );
}
void AVRDevice::getSignature( long * sig0, long * sig1, long * sig2 )
{
if( sig0 == NULL || sig1 == NULL || sig2 == NULL )
throw new ErrorMsg( "Cannot copy signature bytes to NULL-pointers!" );
*sig0 = signature0;
*sig1 = signature1;
*sig2 = signature2;
}
/* end of file */
@@ -0,0 +1,69 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRDevice.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class containing information of device memory sizes etc.
* It also provides funcitons for reading these parameters from
* the PartDescriptionFiles supplied with AVR Studio 4.
*
*
****************************************************************************/
#ifndef AVRDEVICE_HPP
#define AVRDEVICE_HPP
using namespace std;
#include <string>
#include <vector>
#include "Utility.hpp"
#include "XMLParser.hpp"
#include "ErrorMsg.hpp"
class AVRDevice
{
protected:
string deviceName; // The name of the device, eg. ATmega128.
long flashSize; // Size of Flash memory in bytes.
long eepromSize; // Size of EEPROM memory in bytes.
bool hasFuseBits; // Does this device have fuse bits at all?
bool hasExtendedFuseBits; // Does this device have extended fuses?
long signature0;
long signature1;
long signature2; // The three signature bytes, read from XML PartDescriptionFiles.
long pagesize; // Flash page size.
public:
/* Constructor */
AVRDevice( const string & _deviceName );
/* Destructor */
~AVRDevice();
/* Methods */
void readParametersFromAVRStudio( vector<string> & searchpath );
long getFlashSize() { return flashSize; }
long getEEPROMSize() { return eepromSize; }
long getPageSize() { return pagesize; }
bool getFuseStatus() { return hasFuseBits; }
bool getXFuseStatus() { return hasExtendedFuseBits; }
void getSignature( long * sig0, long * sig1, long * sig2 );
};
#endif
@@ -0,0 +1,714 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRInSystemProg.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing an interface to the AVR ISP described
* in Application Note AVR910. This class is derived from AVRPRogrammer.
*
*
****************************************************************************/
#include "AVRInSystemProg.hpp"
#include <sstream>
#include <iomanip>
#define MEM_PROGRESS_GRANULARITY 256 // For use with progress indicator.
/* Constructor */
AVRInSystemProg::AVRInSystemProg( CommChannel * _comm ) :
AVRProgrammer::AVRProgrammer( _comm )
{
/* No code here */
}
/* Destructor */
AVRInSystemProg::~AVRInSystemProg()
{
/* No code here */
}
bool AVRInSystemProg::enterProgrammingMode()
{
/* Must select a device from the AVRISP device code table first */
comm->sendByte( 'T' );
comm->sendByte( 0x64 ); // Select ATmega163, any device in the table will do.
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Entering programming mode failed! "
"Programmer did not return CR after 'T'-command." );
/* Send command 'P' */
comm->sendByte( 'P' );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Entering programming mode failed! "
"Programmer did not return CR after 'P'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::leaveProgrammingMode()
{
/* Send command 'L' */
comm->sendByte( 'L' );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Leaving programming mode failed! "
"Programmer did not return CR after 'L'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::chipErase()
{
/* Send command 'e' */
comm->sendByte( 'e' );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Chip erase failed! "
"Programmer did not return CR after 'e'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::readOSCCAL( long pos, long * value )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0x38 );
comm->sendByte( 0x00 );
comm->sendByte( pos );
comm->sendByte( 0x00 ); // Dummy.
comm->flushTX();
*value = comm->getByte();
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "OSCCAL value readout failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::readSignature( long * sig0, long * sig1, long * sig2 )
{
/* Send command 's' */
comm->sendByte( 's' );
comm->flushTX();
/* Get actual signature */
*sig2 = comm->getByte();
*sig1 = comm->getByte();
*sig0 = comm->getByte();
}
bool AVRInSystemProg::checkSignature( long sig0, long sig1, long sig2 )
{
long sig[3];
/* Get signature */
readSignature( sig, sig+1, sig+2 );
/* Compare signature */
if( sig[0] != sig0 || sig[1] != sig1 || sig[2] != sig2 )
{
ostringstream msg;
msg << "Signature does not match selected device! ";
msg << "Actual signature: (" << hex
<< "0x" << setw(2) << sig[0] << " "
<< "0x" << setw(2) << sig[1] << " "
<< "0x" << setw(2) << sig[2] << ") "
<< "Signature from XML-file: (" << hex
<< "0x" << setw(2) << sig0 << " "
<< "0x" << setw(2) << sig1 << " "
<< "0x" << setw(2) << sig2 << ").";
throw new ErrorMsg( msg.str() );
}
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeFlashByte( long address, long value )
{
if( address >= 0x20000 )
throw new ErrorMsg( "Flash addresses above 128k are currently not supported!" );
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Move data if at odd address */
if( address & 0x01 ) // Odd address?
value = (value << 8) | 0x00ff; // Move to high byte of one flash word.
else
value |= 0xff00; // Ensure no-write for high byte.
/* Send low and high byte */
writeFlashLowByte( value & 0xff );
writeFlashHighByte( value >> 8 );
/* Issue page write if required */
if( pagesize != -1 )
{
setAddress( address >> 1 ); // The address could be autoincremented.
writeFlashPage();
}
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeEEPROMByte( long address, long value )
{
if( address >= 0x10000 )
throw new ErrorMsg( "EEPROM addresses above 64k are currently not supported!" );
setAddress( address );
/* Send data */
comm->sendByte( 'D' );
comm->sendByte( value );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing byte to EEPROM failed! "
"Programmer did not return CR after 'D'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeFlash( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Check that pagesize is set */
if( pagesize == -1 )
throw new ErrorMsg( "Programmer pagesize is not set!" );
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start >> 1 ); // Flash operations use word addresses.
/* Need to write one odd byte first? */
address = start;
if( address & 1 )
{
/* Use only high byte */
writeFlashLowByte( 0xff ); // No-write in low byte.
writeFlashHighByte( data->getData( address ) );
address++;
/* Need to write page? */
if( pagesize != -1 )
{
if( !(address % pagesize) ) // Just passed page limit?
{
setAddress( (address-1) >> 1 ); // Set to an address inside the page.
writeFlashPage();
setAddress( address >> 1 );
}
}
}
/* Write words */
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address >> 1 );
/* Write words */
writeFlashLowByte( data->getData( address ) );
writeFlashHighByte( data->getData( address+1 ) );
address += 2;
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
/* Need to write page? */
if( pagesize != -1 )
{
if( (address % pagesize) == 0 ) // Just passed a page boundary?
{
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
setAddress( address >> 1 );
}
}
} while( address < end );
/* Need to write one even byte before finished? */
if( address == end )
{
/* Use only low byte */
writeFlashLowByte( data->getData( address ) );
writeFlashHighByte( 0xff ); // No-write in high byte.
}
/* Need to write page? */
if( pagesize != -1 )
{
if( address == end || // One extra byte written...
(end+1)%pagesize != 0 ) // ...or end is not on page boundary.
{
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
}
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRInSystemProg::readFlash( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
if( pagesize == -1 )
throw new ErrorMsg( "Programmer pagesize is not set!" );
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start >> 1 ); // Flash operations use word addresses.
/* Need to read one odd byte first? */
address = start;
if( address & 1 )
{
/* Read both, but use only high byte */
comm->sendByte( 'R' );
comm->flushTX();
data->setData( address, comm->getByte() ); // High byte.
comm->getByte(); // Dont use low byte.
address++;
}
/* Get words */
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address >> 1 );
/* Get words */
comm->sendByte( 'R' );
comm->flushTX();
data->setData( address+1, comm->getByte() ); // High byte.
data->setData( address, comm->getByte() ); // Low byte.
address += 2;
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
} while( address < end );
/* Need to read one even byte before finished? */
if( address == end )
{
/* Read both, but use only low byte */
comm->sendByte( 'R' );
comm->flushTX();
comm->getByte(); // Dont use high byte.
data->setData( address-1, comm->getByte() ); // Low byte.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeEEPROM( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start );
/* Send data */
address = start;
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address );
/* Send byte */
comm->sendByte( 'D' );
comm->sendByte( data->getData( address ) );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing byte to EEPROM failed! "
"Programmer did not return CR after 'D'-command." );
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
address++;
} while( address <= end );
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRInSystemProg::readEEPROM( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start );
/* Send data */
address = start;
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address );
/* Get byte */
comm->sendByte( 'd' );
comm->flushTX();
data->setData( address, comm->getByte() );
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
address++;
} while( address <= end );
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeLockBits( long bits )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0xac );
comm->sendByte( 0xe0 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( bits );
comm->flushTX();
comm->getByte(); // Ignore return code from SPI communication.
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Writing lock bits failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::readLockBits( long * bits )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0x58 );
comm->sendByte( 0x00 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( 0x00 ); // Dummy.
comm->flushTX();
*bits = comm->getByte();
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Lock byte readout failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeFuseBits( long bits )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0xac );
comm->sendByte( 0xa0 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( bits & 0xff );
comm->flushTX();
comm->getByte(); // Ignore return code from SPI communication.
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Low fuse byte programming failed! "
"Programmer did not return CR after '.'-command." );
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0xac );
comm->sendByte( 0xa8 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( bits >> 8 );
comm->flushTX();
comm->getByte(); // Ignore return code from SPI communication.
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "High fuse byte programming failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::readFuseBits( long * bits )
{
long low, high;
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0x50 );
comm->sendByte( 0x00 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( 0x00 ); // Dummy.
comm->flushTX();
low = comm->getByte();
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Low fuse byte readout failed! "
"Programmer did not return CR after '.'-command." );
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0x58 );
comm->sendByte( 0x08 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( 0x00 ); // Dummy.
comm->flushTX();
high = comm->getByte();
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Low fuse byte readout failed! "
"Programmer did not return CR adter '.'-command." );
/* Put low and high together */
*bits = (high << 8) | low;
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeExtendedFuseBits( long bits )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0xac );
comm->sendByte( 0xa4 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( bits );
comm->flushTX();
comm->getByte(); // Ignore return code from SPI communication.
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Extended fuse byte programming failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::readExtendedFuseBits( long * bits )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0x50 );
comm->sendByte( 0x08 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( 0x00 ); // Dummy.
comm->flushTX();
*bits = comm->getByte();
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Extended fuse byte readout failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::programmerSoftwareVersion( long * major, long * minor )
{
/* Send command 'V' to get software version */
comm->sendByte( 'V' );
comm->flushTX();
/* Get data */
*major = comm->getByte();
*minor = comm->getByte();
return true; // Indicate supported command.
}
bool AVRInSystemProg::programmerHardwareVersion( long * major, long * minor )
{
/* Send command 'v' to get hardware version */
comm->sendByte( 'v' );
comm->flushTX();
/* Get data */
*major = comm->getByte();
*minor = comm->getByte();
return true; // Indicate supported command.
}
void AVRInSystemProg::setAddress( long address )
{
/* Set current address */
comm->sendByte( 'A' );
comm->sendByte( address >> 8 ); // High byte of address.
comm->sendByte( address & 0xff ); // Low byte.
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Setting address for programming operations failed! "
"Programmer did not return CR after 'A'-command." );
}
void AVRInSystemProg::writeFlashLowByte( long value )
{
comm->sendByte( 'c' );
comm->sendByte( value );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash low byte failed! "
"Programmer did not return CR after 'c'-command." );
}
void AVRInSystemProg::writeFlashHighByte( long value )
{
comm->sendByte( 'C' );
comm->sendByte( value );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash high byte failed! "
"Programmer did not return CR after 'C'-command." );
}
void AVRInSystemProg::writeFlashPage()
{
comm->sendByte( 'm' );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash page failed! "
"Programmer did not return CR after 'm'-command." );
}
/* end of file */
@@ -0,0 +1,78 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRInSystemProg.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing an interface to the AVR ISP described
* in Application Note AVR910. This class is derived from AVRPRogrammer.
*
*
****************************************************************************/
#ifndef AVRINSYSTEMPROG_HPP
#define AVRINSYSTEMPROG_HPP
using namespace std;
#include "AVRProgrammer.hpp"
#include "Utility.hpp"
class AVRInSystemProg : public AVRProgrammer
{
protected:
void setAddress( long address );
void writeFlashLowByte( long value ); // Alwyas low byte first...
void writeFlashHighByte( long value ); // ...then high byte.
void writeFlashPage();
public:
/* Constructor */
AVRInSystemProg( CommChannel * _comm );
/* Destructor */
~AVRInSystemProg();
/* Methods */
virtual bool enterProgrammingMode();
virtual bool leaveProgrammingMode();
virtual bool chipErase();
virtual bool readOSCCAL( long pos, long * value );
virtual bool readSignature( long * sig0, long * sig1, long * sig2 );
virtual bool checkSignature( long sig0, long sig1, long sig2 );
virtual bool writeFlashByte( long address, long value );
virtual bool writeEEPROMByte( long address, long value );
virtual bool writeFlash( HEXFile * data );
virtual bool readFlash( HEXFile * data );
virtual bool writeEEPROM( HEXFile * data );
virtual bool readEEPROM( HEXFile * data );
virtual bool writeLockBits( long bits );
virtual bool readLockBits( long * bits );
virtual bool writeFuseBits( long bits );
virtual bool readFuseBits( long * bits );
virtual bool writeExtendedFuseBits( long bits );
virtual bool readExtendedFuseBits( long * bits );
virtual bool programmerSoftwareVersion( long * major, long * minor );
virtual bool programmerHardwareVersion( long * major, long * minor );
};
#endif
@@ -0,0 +1,169 @@
[Project]
FileName=AVROSP.dev
Name=AVROSP
UnitCount=12
Type=1
Ver=1
ObjFiles=
Includes=
Libs=
PrivateResource=
ResourceIncludes=
MakeIncludes=
Compiler=
CppCompiler=
Linker=
IsCpp=1
Icon=
ExeOutput=
ObjectOutput=
OverrideOutput=0
OverrideOutputName=AVROSP.exe
HostApplication=
Folders=
CommandLine= -dATmega16 -if\temp\rnd8KB.hex -pf
IncludeVersionInfo=0
SupportXPThemes=0
CompilerSet=0
CompilerSettings=000000000000000100
UseCustomMakefile=0
CustomMakefile=
[Unit1]
FileName=main.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[VersionInfo]
Major=0
Minor=1
Release=1
Build=1
LanguageID=1033
CharsetID=1252
CompanyName=
FileVersion=
FileDescription=Developed using the Dev-C++ IDE
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
ProductName=
ProductVersion=
AutoIncBuildNr=0
[Unit2]
FileName=CommChannel.cpp
CompileCpp=1
Folder=Serialtest
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit3]
FileName=ErrorMsg.cpp
CompileCpp=1
Folder=Serialtest
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit4]
FileName=JobInfo.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit5]
FileName=AVRDevice.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit6]
FileName=HEXParser.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit7]
FileName=XMLParser.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit8]
FileName=AVRBootloader.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit9]
FileName=AVRProgrammer.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit10]
FileName=Utility.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit11]
FileName=SerialPort.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit12]
FileName=AVRInSystemProg.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
@@ -0,0 +1,70 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRProgrammer.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : An abstract class containing a framework for a generic
* programmer for AVR parts. Reading and writing Flash, EEPROM
* lock bits and all fuse bits and reading OSCCAL and reading
* signature bytes are supported.
*
*
****************************************************************************/
#include "AVRProgrammer.hpp"
/* Constructor */
AVRProgrammer::AVRProgrammer( CommChannel * _comm ) :
pagesize( -1 )
{
if( _comm == NULL )
throw new ErrorMsg( "NULL pointer provided for communication channel!" );
comm = _comm;
}
/* Destructor */
AVRProgrammer::~AVRProgrammer()
{
/* No code here */
}
string AVRProgrammer::readProgrammerID( CommChannel * _comm )
{
string id( "1234567" ); // Reserve 7 characters.
if( _comm == NULL )
throw new ErrorMsg( "NULL pointer provided for communication channel!" );
/* Synchonize with programmer */
for( int i = 0; i < 10; i++ )
_comm->sendByte( 27 ); // Send ESC
/* Send 'S' command to programmer */
_comm->sendByte( 'S' );
_comm->flushTX();
/* Read 7 characters */
for( long i = 0; i < id.size(); i++ )
{
id[i] = _comm->getByte();
}
return id;
}
/* end of file */
@@ -0,0 +1,84 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRProgrammer.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : An abstract class containing a framework for a generic
* programmer for AVR parts. Reading and writing Flash, EEPROM
* lock bits and all fuse bits and reading OSCCAL and reading
* signature bytes are supported.
*
*
****************************************************************************/
#ifndef AVRPROGRAMMER_HPP
#define AVRPROGRAMMER_HPP
using namespace std;
#include "ErrorMsg.hpp"
#include "HEXParser.hpp"
#include "CommChannel.hpp"
class AVRProgrammer
{
protected:
long pagesize; // Flash page size.
CommChannel * comm;
public:
/* Constructor */
AVRProgrammer( CommChannel * _comm );
/* Destructor */
~AVRProgrammer();
/* Static member */
static string readProgrammerID( CommChannel * _comm ); // Reads 7-character ID.
/* Methods */
void setPagesize( long _pagesize ) { pagesize = _pagesize; }
virtual bool enterProgrammingMode() = 0;
virtual bool leaveProgrammingMode() = 0;
virtual bool chipErase() = 0;
virtual bool readOSCCAL( long pos, long * value ) = 0;
virtual bool readSignature( long * sig0, long * sig1, long * sig2 ) = 0;
virtual bool checkSignature( long sig0, long sig1, long sig2 ) = 0;
virtual bool writeFlashByte( long address, long value ) = 0;
virtual bool writeEEPROMByte( long address, long value ) = 0;
virtual bool writeFlash( HEXFile * data ) = 0;
virtual bool readFlash( HEXFile * data ) = 0;
virtual bool writeEEPROM( HEXFile * data ) = 0;
virtual bool readEEPROM( HEXFile * data ) = 0;
virtual bool writeLockBits( long bits ) = 0;
virtual bool readLockBits( long * bits ) = 0;
virtual bool writeFuseBits( long bits ) = 0;
virtual bool readFuseBits( long * bits ) = 0;
virtual bool writeExtendedFuseBits( long bits ) = 0;
virtual bool readExtendedFuseBits( long * bits ) = 0;
virtual bool programmerSoftwareVersion( long * major, long * minor ) = 0;
virtual bool programmerHardwareVersion( long * major, long * minor ) = 0;
};
#endif
@@ -0,0 +1,38 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : CommChannel.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : An abstract class for general byte-by-byte communication.
* Serialport, USB, TCP/IP or similar implementations can be derived
* from this class to create a technology-independent
* communication interface.
*
* This abstract class does not provide any constructor as it is
* too specific for this generalized class. Derived classes should
* implement their own constructors for specific communication devices.
*
*
****************************************************************************/
#include "CommChannel.hpp"
/* Destructor */
CommChannel::~CommChannel()
{
/* no code here */
}
/* end of file */
@@ -0,0 +1,61 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : CommChannel.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : An abstract class for general byte-by-byte communication.
* Serialport, USB, TCP/IP or similar implementations can be derived
* from this class to create a technology-independent
* communication interface.
*
* This abstract class does not provide any constructor as it is
* too specific for this generalized class. Derived classes should
* implement their own constructors for specific communication devices.
*
*
****************************************************************************/
#ifndef COMMCHANNEL_HPP
#define COMMCHANNEL_HPP
using namespace std;
class CommChannel
{
public:
// Destructor
virtual ~CommChannel() = 0;
// Open the communication channel.
virtual void openChannel() = 0;
// Close the communication channel.
virtual void closeChannel() = 0;
// Transmit a single byte.
virtual void sendByte( long data ) = 0;
// Receive a single byte.
virtual long getByte() = 0;
// Flush the transmit buffer.
virtual void flushTX() = 0;
// Flush the receive buffer.
virtual void flushRX() = 0;
// Transmit multiple bytes.
virtual void sendMultiple( unsigned char * data, long bufsize ) = 0;
};
#endif
@@ -0,0 +1,46 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : ErrorMsg.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing a container for general error messages. This
* class can be thrown as an exception.
*
*
****************************************************************************/
#include "ErrorMsg.hpp"
ErrorMsg::ErrorMsg( const string & _message ) :
message( _message )
{
// No code here.
}
/* Destructor */
ErrorMsg::~ErrorMsg()
{
// No code here.
}
/* Get message */
const string & ErrorMsg::What()
{
return message;
}
/* end of file */
@@ -0,0 +1,49 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : ErrorMsg.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing a container for general error messages. This
* class can be thrown as an exception.
*
*
****************************************************************************/
#ifndef ERRORMSG_HPP
#define ERRORMSG_HPP
using namespace std;
#include <stdlib.h>
#include <iostream>
#include <string>
class ErrorMsg
{
protected:
string message; // Contains the error message.
public:
// Constructors taking the string as parameter.
ErrorMsg( const string & _message );
// Destructor
~ErrorMsg();
// Function returning the error msg.
virtual const string & What();
};
#endif
@@ -0,0 +1,364 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : HEXParser.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A simple Intel HEX file format reader/writer.
*
*
****************************************************************************/
#include "HEXParser.hpp"
/* Internal struct for managing HEX records */
struct HEXRecord // Intel HEX file record
{
unsigned char length; // Record length in number of data bytes.
unsigned long offset; // Offset address.
unsigned char type; // Record type.
unsigned char * data; // Optional data bytes.
};
void HEXFile::writeRecord( ofstream & f, HEXRecord * recp )
{
unsigned char checksum;
long recordPos; // Position inside record data field
/* Calculate checksum */
checksum = recp->length;
checksum += (unsigned char) ((recp->offset >> 8) & 0xff);
checksum += (unsigned char) (recp->offset & 0xff);
checksum += recp->type;
/* Write record header */
f.fill('0');
f << ":" << hex
<< setw(2) << (long) recp->length
<< setw(4) << (long) recp->offset
<< setw(2) << (long) recp->type;
/* Write data bytes */
for( recordPos = 0; recordPos < recp->length; recordPos++ )
{
checksum += recp->data[ recordPos ]; // Further checksum calculation
f << hex << setw(2) << (long) recp->data[ recordPos ];
}
/* Write checksum */
checksum = 0 - checksum; // Final checksum preparation
f << setw(2) << (long) checksum << endl;
/* Check for errors */
if( !f.good() )
throw new ErrorMsg( "Error writing HEX record to file!" );
}
void HEXFile::parseRecord( const string & hexLine, HEXRecord * recp )
{
unsigned char checksum;
long recordPos; // Position inside record data fields.
if( hexLine.size() < 11 ) // At least 11 characters.
throw new ErrorMsg( "Wrong HEX file format, missing fields! "
"Line from file was: (" + hexLine + ")." );
/* Check format for line */
if( hexLine[0] != ':' ) // Always start with colon.
throw new ErrorMsg( "Wrong HEX file format, does not start with colon! "
"Line from file was: (" + hexLine + ")." );
/* Parse length, offset and type */
recp->length = Util.convertHex( hexLine.substr( 1, 2 ) );
recp->offset = Util.convertHex( hexLine.substr( 3, 4 ) );
recp->type = Util.convertHex( hexLine.substr( 7, 2 ) );
/* We now know how long the record should be */
if( hexLine.size() < (11+recp->length*2) )
throw new ErrorMsg( "Wrong HEX file format, missing fields! "
"Line from file was: (" + hexLine + ")." );
/* Process checksum */
checksum = recp->length;
checksum += (unsigned char) ((recp->offset >> 8) & 0xff);
checksum += (unsigned char) (recp->offset & 0xff);
checksum += recp->type;
/* Parse data fields */
if( recp->length )
{
recp->data = new unsigned char[ recp->length ];
/* Read data from record */
for( recordPos = 0; recordPos < recp->length; recordPos++ )
{
recp->data[ recordPos ] = Util.convertHex( hexLine.substr( 9 + recordPos*2, 2 ) );
checksum += recp->data[ recordPos ];
}
}
/* Correct checksum? */
checksum += Util.convertHex( hexLine.substr( 9 + recp->length*2, 2 ) );
if( checksum != 0 )
{
throw new ErrorMsg( "Wrong checksum for HEX record! "
"Line from file was: (" + hexLine + ")." );
}
}
/* Constructor */
HEXFile::HEXFile( long buffersize, long value )
{
if( buffersize <= 0 )
throw new ErrorMsg( "Cannot have zero-size HEX buffer!" );
data = new unsigned char[ buffersize ];
if( !data )
throw new ErrorMsg( "Memory allocation failed for HEX-line-buffer!" );
size = buffersize;
clearAll( value );
}
/* Destructor */
HEXFile::~HEXFile()
{
if( data ) delete data;
}
void HEXFile::readFile( const string & _filename )
{
ifstream f;
string hexLine; // Contains one line of the HEX file.
HEXRecord rec; // Temp record.
long baseAddress; // Base address for extended addressing modes.
long dataPos; // Data position in record.
/* Attempt to open file */
f.open( _filename.c_str(), ios::in );
if( !f )
throw new ErrorMsg( "Error opening HEX file for input!" );
/* Prepare */
baseAddress = 0;
start = size;
end = 0;
/* Parse records */
f >> hexLine; // Read one line.
while( !f.eof() )
{
Util.progress( "#" ); // Advance progress indicator.
/* Process record according to type */
parseRecord( hexLine, &rec );
switch( rec.type )
{
case 0x00 : // Data record ?
/* Copy data */
if( baseAddress + rec.offset + rec.length > size )
throw new ErrorMsg( "HEX file defines data outside buffer limits! "
"Make sure file does not contain data outside device "
"memory limits. "
"Line from file was: (" + hexLine + ")." );
for( dataPos = 0; dataPos < rec.length; dataPos++ )
data[ baseAddress + rec.offset + dataPos ] = rec.data[ dataPos ];
/* Update byte usage */
if( baseAddress + rec.offset < start )
start = baseAddress + rec.offset;
if( baseAddress + rec.offset + rec.length - 1 > end )
end = baseAddress + rec.offset + rec.length - 1;
break;
case 0x02 : // Extended segment address record ?
baseAddress = (rec.data[0] << 8) | rec.data[1];
baseAddress <<= 4;
break;
case 0x03 : // Start segment address record ?
break; // Ignore it, since we have no influence on execution start address.
case 0x04 : // Extended linear address record ?
baseAddress = (rec.data[0] << 8) | rec.data[1];
baseAddress <<= 16;
break;
case 0x05 : // Start linear address record ?
break; // Ignore it, since we have no influence on exectuion start address.
case 0x01 : // End of file record ?
f.close();
Util.progress( "\r\n" ); // Finish progress indicator.
return;
default:
throw new ErrorMsg( "Unsupported HEX record format! "
"Line from file was: (" + hexLine + ")." );
}
f >> hexLine; // Read next line.
}
/* We should not end up here */
throw new ErrorMsg( "Premature end of file encountered! Make sure file "
"contains an EOF-record." );
}
void HEXFile::writeFile( const string & _filename )
{
ofstream f;
HEXRecord rec; // Temp record.
long baseAddress; // Absolute data position.
long offset; // Offset from base address.
long dataPos; // Position inside data record.
enum
{
_first,
_writing,
_passed64k
} status; // Write status, see usage below.
/* Attempt to create file */
f.open( _filename.c_str(), ios::out );
if( !f )
throw new ErrorMsg( "Error opening HEX file for output!" );
/* Prepare */
status = _first;
rec.data = new unsigned char[ 16 ]; // Use only 16 byte records.
baseAddress = start & ~0xffff; // 64K aligned address.
offset = start & 0xffff; // Offset from the aligned address.
dataPos = 0;
/* Write first base address record to HEX file */
rec.length = 2;
rec.offset = 0;
rec.type = 0x02;
rec.data[1] = 0x00;
rec.data[0] = baseAddress >> 12; // Give 4k page index.
writeRecord( f, &rec ); // Write the HEX record to file.
/* Write all bytes in used range */
do
{
/* Put data into record */
rec.data[ dataPos ] = data[ baseAddress + offset + dataPos ];
dataPos++;
/* Check if we need to write out the current data record */
if( offset + dataPos >= 0x10000 || // Reached 64k boundary?
dataPos >= 16 || // Data record full?
baseAddress + offset + dataPos > end ) // End of used range reached?
{
/* Write current data record */
rec.length = dataPos;
rec.offset = offset;
rec.type = 0x00; // Data record.
Util.progress( "#" ); // Advance progress indicator.
writeRecord( f, &rec );
offset += dataPos;
dataPos = 0;
}
/* Check if we have passed a 64k boundary */
if( offset + dataPos >= 0x10000 )
{
/* Update address pointers */
offset -= 0x10000;
baseAddress += 0x10000;
/* Write new base address record to HEX file */
rec.length = 2;
rec.offset = 0;
rec.type = 0x02;
rec.data[0] = baseAddress >> 12; // Give 4k page index.
rec.data[1] = 0x00;
writeRecord( f, &rec ); // Write the HEX record to file.
}
} while( baseAddress + offset + dataPos <= end );
/* Write EOF record */
rec.length = 0;
rec.offset = 0;
rec.type = 0x01;
writeRecord( f, &rec );
f.close();
Util.progress( "\r\n" ); // Finish progress indicator.
}
void HEXFile::setUsedRange( long _start, long _end )
{
if( _start < 0 || _end >= size || _start > _end )
throw new ErrorMsg( "Invalid range! Start must be 0 or larger, end must be "
"inside allowed memory range." );
start = _start;
end = _end;
}
void HEXFile::clearAll( long value )
{
for( long i = 0; i < size; i++ )
data[i] = (unsigned char) (value & 0xff);
}
long HEXFile::getData( long address )
{
if( address < 0 || address >= size )
throw new ErrorMsg( "Address outside legal range!" );
return data[ address ];
}
void HEXFile::setData( long address, long value )
{
if( address < 0 || address >= size )
throw new ErrorMsg( "Address outside legal range!" );
data[ address ] = (unsigned char) (value & 0xff);
}
/* end of file */
@@ -0,0 +1,67 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : HEXParser.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A simple Intel HEX file format reader/writer.
*
*
****************************************************************************/
#ifndef HEXPARSER_HPP
#define HEXPARSER_HPP
using namespace std;
#include "ErrorMsg.hpp"
#include "Utility.hpp"
#include <iostream>
#include <fstream>
#include <iomanip>
struct HEXRecord; // Preliminary definition.
class HEXFile
{
protected:
unsigned char * data; // Holds the data bytes.
long start, end; // Used data range.
long size; // Size of databuffer.
void writeRecord( ofstream & f, HEXRecord * recp );
void parseRecord( const string & hexLine, HEXRecord * recp );
public:
/* Constructor */
HEXFile( long buffersize, long value = 0xff );
/* Destructor */
~HEXFile();
/* Methods */
void readFile( const string & _filename ); // Read data from HEX file.
void writeFile( const string & _filename ); // Write data to HEX file.
void setUsedRange( long _start, long _end ); // Sets the used range.
void clearAll( long value = 0xff ); // Set databuffer to this value.
long getRangeStart() { return start; }
long getRangeEnd() { return end; }
long getData( long address );
void setData( long address, long value );
long getSize() { return size; }
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,105 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : JobInfo.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class holding information on what the AVR Open-Source Programmer
* should do. The information is derived from the command-line.
*
*
****************************************************************************/
#ifndef JOBINFO_HPP
#define JOBINFO_HPP
using namespace std;
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include "ErrorMsg.hpp"
#include "AVRProgrammer.hpp"
#include "AVRBootloader.hpp"
#include "AVRInSystemProg.hpp"
#include "AVRDevice.hpp"
#include "SerialPort.hpp"
#include "Utility.hpp"
class JobInfo
{
protected:
long convertHex( char * txt );
void help();
void doDeviceIndependent( AVRProgrammer * prog );
void doDeviceDependent( AVRProgrammer * prog, AVRDevice * avr );
bool showHelp; // Show help screen?
bool silentMode; // No text output?
bool noProgressIndicator; // Do not show progress indicators?
bool readSignature; // Output signature bytes to screen?
bool chipErase; // Erase chip before any programming operations?
bool getHWrevision; // Get hardware revision of programmer?
bool getSWrevision; // Get software revision of programmer?
bool programFlash; // Flash programming desired?
bool programEEPROM; // E2 programming desired?
bool readFlash; // Flash readout desired?
bool readEEPROM; // E2 readout desired?
bool verifyFlash; // Flash verification desired?
bool verifyEEPROM; // E2 verification desired?
bool readLockBits; // Lock bit readout desired?
bool readFuseBits; // Fuse bit readout desired?
bool readOSCCAL; // Read or use specified OSCCAL value, if -O is used?
string deviceName; // Specified device name.
string inputFileFlash; // Input file for Flash writing and verification.
string inputFileEEPROM; // Input file for E2 writing and verification.
string outputFileFlash; // Output file for Flash readout.
string outputFileEEPROM; // Output file for E2 readout.
long OSCCAL_Parameter; // Value of the -O parameter, -1 if unspecified.
long OSCCAL_FlashAddress; // Where to put OSCCAL value in flash, -1 if not.
long OSCCAL_EEPROMAddress; // Where to put OSCCAL value in E2, -1 if not.
long programLockBits; // Change lock bits to this value, -1 if not.
long verifyLockBits; // Verify lock bits against this value, -1 if not.
long programFuseBits; // Change fuse bits to this value, -1 if not.
long programExtendedFuseBits; // Same as above for extended fuse bits.
long verifyFuseBits; // Verify fuse bits against this value, -1 if not.
long verifyExtendedFuseBits; // Same as above for extended fuse bits.
long memoryFillPattern; // Fill unspecified locations, -1 if not.
long flashStartAddress; // Limit Flash operations, -1 if not.
long flashEndAddress; // ...to this address, inclusive, -1 if not.
long eepromStartAddress; // Same as above for E2.
long eepromEndAddress; // ...
long comPort; // Desired COM port to use, -1 if unspecified.
vector<string> searchpath; // Search path for XML-files.
public:
JobInfo(); // Constructor
void parseCommandline( int argc, char *argv[] );
void doJob();
};
#endif
@@ -0,0 +1,194 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : SerialPort.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing serial communication through the PC COM port.
* This class is derived from the CommChannel abstract class.
*
*
****************************************************************************/
#include "SerialPort.hpp"
/* Constructor */
SerialPort::SerialPort( long _portNumber, long _timeout )
{
if( _timeout < 0 )
throw new ErrorMsg( "Negative COM-port timeout not allowed!" );
if( _portNumber < 1 || _portNumber > 8 )
throw new ErrorMsg( "Only COM1 to COM8 is supported!" );
/* Initialize internal parameters */
portNumber = _portNumber;
timeout = _timeout;
channelOpen = false;
}
/* Destructor */
SerialPort::~SerialPort()
{
closeChannel();
}
/* Open the communication channel */
void SerialPort::openChannel()
{
char comName[] = "COMx";
COMMTIMEOUTS comTimeouts;
/* Check if channel already open */
if( channelOpen )
throw new ErrorMsg( "Channel already open! Cannot open port twice." );
/* Generate COM filename and attempt open */
comName[3] = '0' + portNumber;
serialHandle = CreateFile( comName, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
/* Print error and return if failed opening port */
if( serialHandle == INVALID_HANDLE_VALUE )
throw new ErrorMsg( "Error opening COM port!" );
channelOpen = true;
/* Store old COM port settings */
if( !GetCommTimeouts( serialHandle, &oldComTimeouts ) )
throw new ErrorMsg( "Error reading COM port settings!" );
/* Get another copy of the COM settings, and change them */
if( !GetCommTimeouts( serialHandle, &comTimeouts ) )
throw new ErrorMsg( "Error reading COM port settings!" );
comTimeouts.ReadIntervalTimeout = MAXDWORD;
comTimeouts.ReadTotalTimeoutConstant = 0;
comTimeouts.ReadTotalTimeoutMultiplier = 0;
/* Apply new settings */
if( !SetCommTimeouts( serialHandle, &comTimeouts ) )
throw new ErrorMsg( "Error changing COM port settings!" );
}
/* Close the communication channel */
void SerialPort::closeChannel()
{
if( !channelOpen )
return;
/* Restore old COM parameters */
if( !SetCommTimeouts( serialHandle, &oldComTimeouts ) )
throw new ErrorMsg( "Error changing COM port settings!" );
/* Release port */
if( serialHandle != INVALID_HANDLE_VALUE )
if( !CloseHandle( serialHandle ) )
throw new ErrorMsg( "Error closing COM port!" );
channelOpen = false;
}
/* Transmit a single byte */
void SerialPort::sendByte( long data )
{
DWORD written;
/* Check if channel is open */
if( !channelOpen )
throw new ErrorMsg( "Channel not open! Cannot send to unopened channel." );
/* Attempt writing */
if( !WriteFile( serialHandle, &data, 1, &written, NULL ) )
throw new ErrorMsg( "Error writing byte to COM port!" );
}
/* Receive a single byte */
long SerialPort::getByte()
{
time_t startTime;
startTime = time( NULL ); // Read current time in seconds
DWORD readnum;
unsigned char data;
/* Check if channel is open */
if( !channelOpen )
throw new ErrorMsg( "Channel not open! Cannot read from unopened channel." );
/* Attempt receiving byte until timeout limit exceeded */
do
{
/* Read byte from port */
if( !ReadFile( serialHandle, &data, 1, &readnum, NULL ) )
{
throw new ErrorMsg( "Error reading byte from COM port!" );
}
if( readnum == 1 )
return ((long) data) & 0xff;
} while( time(NULL) - startTime < timeout );
/* Timeout */
throw new ErrorMsg( "Timeout during COM-port read operation!" );
}
/* Flush the transmit buffer */
void SerialPort::flushTX()
{
/* Check if channel is open */
if( !channelOpen )
throw new ErrorMsg( "Channel not open! Cannot flush an unopened channel." );
/* Purge data from write buffer */
if( !PurgeComm( serialHandle, PURGE_TXCLEAR ) )
throw new ErrorMsg( "Error flushing COM port TX buffer!" );
}
/* Flush the receive buffer */
void SerialPort::flushRX()
{
/* Check if channel is open */
if( !channelOpen )
throw new ErrorMsg( "Channel not open! Cannot flush an unopened channel." );
/* Purge data from write buffer */
if( !PurgeComm( serialHandle, PURGE_RXCLEAR ) )
throw new ErrorMsg( "Error flushing COM port RX buffer!" );
}
/* Transmit multiple bytes */
void SerialPort::sendMultiple( unsigned char * data, long bufsize )
{
DWORD written;
/* Check if channel is open */
if( !channelOpen )
throw new ErrorMsg( "Channel not open! Cannot write to unopened channel." );
/* Attempt writing */
if( !WriteFile( serialHandle, data, bufsize, &written, NULL ) )
throw new ErrorMsg( "Error writing multiple bytes to COM port!" );
}
/* end of file */
@@ -0,0 +1,75 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : SerialPort.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing serial communication through the PC COM port.
* This class is derived from the CommChannel abstract class.
*
*
****************************************************************************/
#ifndef SERIALPORT_HPP
#define SERIALPORT_HPP
using namespace std;
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <time.h>
#include <iostream>
#include "CommChannel.hpp"
#include "ErrorMsg.hpp"
class SerialPort : public CommChannel
{
protected:
long portNumber; // COMx port number.
long timeout; // Desired timeout limit when receiving data.
HANDLE serialHandle; // Win32 device handle for the com port.
COMMTIMEOUTS oldComTimeouts; // Store old serial port timeout parameters.
bool channelOpen; // Is channel open?
public:
// Constructor taking port number, baudrate and
// timeout limit as parameters.
SerialPort( long portnumber, long timeout );
// Destructor.
~SerialPort();
// Open the communication channel.
virtual void openChannel();
// Close the communication channel.
virtual void closeChannel();
// Transmit a single byte.
virtual void sendByte( long data );
// Receive a single byte.
virtual long getByte();
// Flush the transmit buffer.
virtual void flushTX();
// Flush the receive buffer.
virtual void flushRX();
// Transmit multiple bytes.
virtual void sendMultiple( unsigned char * data, long bufsize );
};
#endif
@@ -0,0 +1,181 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : Utility.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class holding misc. utility methods used in AVROSP.
*
*
****************************************************************************/
#include "Utility.hpp"
#include <iostream>
#include <fstream>
#include <stdlib.h>
/* Global object */
Utility Util;
/* Constructor */
Utility::Utility() :
noLog( false ),
noProgress( false )
{
/* No code here */
}
/* Destructor */
Utility::~Utility()
{
/* No code here */
}
void Utility::log( const string & txt )
{
if( !noLog )
cout << txt;
}
void Utility::progress( const string & txt )
{
if( !noProgress )
cout << txt;
}
long Utility::convertHex( const string & txt )
{
long result = 0;
long digit;
long i;
if( txt.size() == 0 )
throw new ErrorMsg( "Cannot convert zero-length hex-string to number!" );
if( txt.size() > 8 )
throw new ErrorMsg( "Hex conversion overflow! Too many hex digits in string." );
for( i = 0; i < txt.size(); i++ )
{
/* Convert hex digit */
if( txt[i] >= '0' && txt[i] <= '9' )
digit = txt[i] - '0';
else if( txt[i] >= 'a' && txt[i] <= 'f' )
digit = txt[i] - 'a' + 10;
else if( txt[i] >= 'A' && txt[i] <= 'F' )
digit = txt[i] - 'A' + 10;
else
throw new ErrorMsg( "Invalid hex digit found!" );
/* Add digit as least significant 4 bits of result */
result = (result << 4) | digit;
}
return result;
}
string Utility::convertLong( long num, long radix )
{
char buf[18];
string res;
itoa( num, buf, radix );
res = buf;
return res;
}
void Utility::parsePath( vector<string> & list )
{
/* Get environment variable and parse if it exists */
char * pathptr = getenv( "PATH" );
if( pathptr != NULL && pathptr[0] != 0 ) {
string path = pathptr;
int pos;
while( (pos = path.find_first_of( ";" )) < path.length() ) {
list.push_back( path.substr( 0, pos ) );
path.erase( 0, pos+1 );
}
list.push_back( path ); // Last directory.
}
}
bool Utility::fileExists( string filename )
{
/* Attempt to open file */
ifstream f;
f.open( filename.c_str(), ios::in );
if( !f ) {
return false;
} else {
f.close();
return true;
}
}
void Utility::saveString( string txt, string filename )
{
ofstream f;
f.open( filename.c_str(), ios::out );
if( !f )
throw new ErrorMsg( "Error opening HEX file for output!" );
f << txt;
f.close();
}
#ifndef NOREGISTRY
string Utility::getRegistryValue( const string & path, const string & value )
{
/* Code modified from MSDN */
const long BUFSIZE=1000;
string result;
HKEY hKey;
char szAVRPath[BUFSIZE];
DWORD dwBufLen=BUFSIZE;
LONG lRet;
/* Open key */
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, path.c_str(), 0, KEY_QUERY_VALUE, &hKey );
if( lRet != ERROR_SUCCESS )
throw new ErrorMsg( "Error when opening registry key: (" + path + ")!" );
/* Get value */
lRet = RegQueryValueEx( hKey, value.c_str(), NULL, NULL, (LPBYTE) szAVRPath, &dwBufLen);
if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) )
throw new ErrorMsg( "Error when reading key value: (" + value + ")!" );
/* Clean up and return result */
RegCloseKey( hKey );
result = szAVRPath;
return result;
}
#endif
/* end of file */
@@ -0,0 +1,70 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : Utility.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class holding misc. utility methods used in AVROSP.
*
*
****************************************************************************/
#ifndef UTILITY_HPP
#define UTILITY_HPP
using namespace std;
#ifndef NOREGISTRY
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <vector>
#include <string>
#include "ErrorMsg.hpp"
class Utility
{
protected:
bool noLog;
bool noProgress;
public:
/* Constructor */
Utility();
/* Destructor */
~Utility();
/* Methods */
void muteLog() { noLog = true; }
void muteProgress() { noProgress = true; }
void log( const string & txt );
void progress( const string & txt );
long convertHex( const string & txt );
string convertLong( long num, long radix = 10 );
void parsePath( vector<string> & list );
bool fileExists( string filename );
void saveString( string txt, string filename );
#ifndef NOREGISTRY
string getRegistryValue( const string & path, const string & value );
#endif
};
extern Utility Util;
#endif
@@ -0,0 +1,637 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : XMLParser.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 3419 $
* Date : $Date: 2008-02-22 09:56:34 +0100 (fr, 22 feb 2008) $
* Updated by : $Author: khole $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A simple XML DOM-like parser. It builds a complete tree from
* the XML file. IT supports <section/> tags, but not tag attributes.
*
*
****************************************************************************/
#include "XMLParser.hpp"
/* Private classes */
enum XMLNodeType
{
xml_node,
xml_subtree
};
/* Abstract class. XMLTree and XMLNode is derived from this class */
class XMLAbstractNode
{
protected:
string name; // Name of this node.
XMLNodeType type;
public:
/* Constructor */
XMLAbstractNode( const string & _name, XMLNodeType _type );
/* Destructor */
~XMLAbstractNode();
/* Methods */
const string & getName();
XMLNodeType getType();
bool isName( const string & _name ); // Compare name to _name.
virtual void print() = 0;
};
/* Class describing a subtree, derived from XMLAbstractNode */
class XMLTree : public XMLAbstractNode
{
protected:
list<XMLAbstractNode *> nodes; // Nodes contained in this tree.
public:
/* Constructor */
XMLTree( const string & _name );
/* Destructor */
~XMLTree();
/* Methods */
void addNode( XMLAbstractNode * newnode );
bool containsNode( const string & _name ); // Searches for name in list.
XMLAbstractNode * getNode( const string & _name );
void print();
};
/* Class describing an ordinary string-valued node, derived from XMLAbstractNode */
class XMLNode : public XMLAbstractNode
{
protected:
string value; // String value.
public:
/* Constructor */
XMLNode( const string & _name, const string & _value );
/* Destructor */
~XMLNode();
/* Methods */
bool isEmpty(); // Contains an empty string?
const string & getValue();
void print();
};
void XMLFile::removeComments( string & txt )
{
long pos = 0; // Everything up to this point is clean.
long startFoundAt; // Comment start and end found at these positions.
long endFoundAt;
/* Search and remove all comment tags */
do
{
/* Search for comment start */
startFoundAt = txt.find( "<!--", pos );
/* Exit the search loop if no comment is found */
if( startFoundAt == string::npos )
{
pos = txt.size();
break;
}
/* Search for comment end */
endFoundAt = txt.find( "-->", startFoundAt );
/* Error if start but no end is found */
if( endFoundAt == string::npos )
throw new ErrorMsg( "Unclosed comment tag encountered! "
"Comment start-tag '<!--' found, but no "
"closing '-->'." );
/* Remove comment tag */
txt.erase( startFoundAt, endFoundAt - startFoundAt + 3 );
pos = startFoundAt; // Prepare for next search.
} while( pos < txt.size() );
}
void XMLFile::removeStartXML( string & txt )
{
long pos = 0; // Everything up to this point is clean.
long startFoundAt; // Comment start and end found at these positions.
long endFoundAt;
/* Search and remove the <?xml tag */
startFoundAt = txt.find( "<?xml", pos );
/* Exit the search loop if not found */
if( startFoundAt == string::npos )
{
pos = txt.size();
return;
}
/* Search for end */
endFoundAt = txt.find( ">", startFoundAt );
/* Remove tag */
txt.erase( startFoundAt, endFoundAt - startFoundAt );
}
void XMLFile::removeAttributes( string & txt )
{
long pos; // Everything up to this point is clean.
long startFoundAt; // Tag start and end found at these positions.
long endFoundAt;
long spaceFoundAt; // Space before attribute found at this position.
long slashFoundAt; // Ending slash found at this position.
/* Convert all whitespace to plain spaces, just to make things easier */
for( pos = 0; pos < txt.size(); pos++ )
{
if( txt[pos] == '\n' || txt[pos] == '\r' || txt[pos] == '\t' )
txt.replace( pos, 1, " " );
}
pos = 0;
/* Search and clean all tags */
do
{
/* Search for tag start */
startFoundAt = txt.find( "<", pos );
/* Exit loop if no tag is found */
if( startFoundAt == string::npos )
break;
/* Search for comment end */
endFoundAt = txt.find( ">", startFoundAt );
/* Error if start but no end is found */
if( endFoundAt == string::npos )
throw new ErrorMsg( "Unclosed tag encountered! "
"Tag start token '<' found, but not "
"closing '>'." );
/* Remove whitespace before tag name */
while( txt[startFoundAt+1] == ' ' )
{
txt.erase( startFoundAt+1, 1 ); // Remove.
endFoundAt--; // String has now shrunk.
}
/* Search for space before attributes */
spaceFoundAt = txt.find( " ", startFoundAt );
if( spaceFoundAt < endFoundAt && spaceFoundAt != string::npos ) // Space found inside tag?
{
// If empty tag, we dont want to remove the / in />
if ( txt.at(endFoundAt-1) == '/' )
{
endFoundAt--;
}
/* Remove attributes */
txt.erase( spaceFoundAt, endFoundAt - spaceFoundAt );
endFoundAt -= endFoundAt - spaceFoundAt; // String has now shrunk.
}
pos = endFoundAt + 1; // Prepare for next search.
} while( pos < txt.size() );
}
void XMLFile::readFile( const string & _filename )
{
ifstream f; // XML file stream.
string contents; // XML file contents.
string templine;
/* Attempt to open file */
f.open( _filename.c_str(), ios::in );
if( !f )
throw new ErrorMsg( "Error opening XML file for input!" );
/* Read everything into the contents string */
contents.erase();
templine.erase();
do
{
contents += templine + " ";
f >> templine; // This will cause EOF only when reading from the end.
} while( !f.eof() );
f.close();
/* Remove comments and tag attributes */
removeComments( contents );
removeAttributes( contents );
removeStartXML ( contents );
/* Create root node */
root = new XMLTree( "root" );
parseFragment( contents, root );
Util.progress( "\r\n" ); // Finish progress indicator.
}
void XMLFile::parseFragment( string & fragment, XMLTree * parent )
{
long startFoundAt; // Tag start and end found at these positions.
long endFoundAt;
string closingString; // Search string used for finding closing tag.
long closingFoundAt; // Closing tag found at this position.
string tagName; // These are for recently created nodes.
string tagValue;
XMLTree * newTree;
XMLNode * newNode;
long nestedFoundAt; // Nested tags found at this position.
/* Find top level tags */
Util.progress( "#" ); // Advance progress indicator.
while( true ) // Wait for break from inside.
{
/* Find start of tag */
startFoundAt = fragment.find( "<", 0 );
if( startFoundAt == string::npos ) // Exit loop if no tags found.
break;
/* Check if this is a closing tag for a higher level tag pair */
if( fragment[startFoundAt+1] == '/' )
break; // Exit loop.
/* Find end of tag */
endFoundAt = fragment.find( ">", startFoundAt );
if( endFoundAt == string::npos ) // Error if end not found.
throw new ErrorMsg( "Unclosed tag encountered! "
"Tag start token '<' found, but no "
"closing '>'." );
/* Extract name of tag */
tagName = fragment.substr( startFoundAt+1, endFoundAt-startFoundAt-1 );
if( tagName.size() == 0 ) // Error if zero-length tag name.
throw new ErrorMsg( "Unnamed tag encountered! "
"No text between '<' and '>'." );
/* Remove tag from fragment */
fragment.erase( 0, startFoundAt+tagName.size()+2 );
/* Check if it is an empty tag */
if( tagName[tagName.size()-1] == '/' )
{
/* Create a new empty ordinary node */
tagName.erase( tagName.size()-1 ); // Remove the slash.
tagValue.erase(); // This tag has no value.
newNode = new XMLNode( tagName, tagValue );
parent->addNode( newNode );
} else
{
/* Find the matching closing tag for this pair */
closingString.erase();
closingString += "</" + tagName + ">";
closingFoundAt = fragment.find( closingString, 0 );
if( closingFoundAt == string::npos ) // Error if not found.
throw new ErrorMsg( "Closing tag not found! "
"Opening tag '<" + tagName + ">' found, "
"but not closing '" + closingString + "'." );
/* Check for tags inside this tag pair, indicating a subtree */
nestedFoundAt = fragment.find( "<", 0 );
if( nestedFoundAt == closingFoundAt ) // No other tags inside?
{
/* Extract contents within tag pair */
tagValue = fragment.substr( 0, closingFoundAt );
/* Create new ordinary node */
newNode = new XMLNode( tagName, tagValue );
parent->addNode( newNode );
} else
{
/* Create new subtree and parse it's fragment */
newTree = new XMLTree( tagName );
parent->addNode( newTree );
parseFragment( fragment, newTree );
/* Check that we can still find the closing tag */
closingFoundAt = fragment.find( closingString, 0 );
if( closingFoundAt == string::npos )
throw new ErrorMsg( "Closing tag not found! "
"Opening tag '<" + tagName + ">' found, "
"but not closing '" + closingString + "'." );
}
/* Remove value and closing tag from fragment */
fragment.erase( 0, closingFoundAt + closingString.size() );
}
};
}
/* Constructor */
XMLFile::XMLFile( const string & _filename )
{
readFile( _filename );
}
/* Destructor */
XMLFile::~XMLFile()
{
if( root != NULL )
delete root;
}
bool XMLFile::exists( const string & path )
{
XMLAbstractNode * currentNode = root;
XMLTree * currentTree;
long namePos; // Position for current tag name in path.
long separatorPos; // Position for #-separator following tag name.
string tagName; // Current tag name.
namePos = 0;
while( true ) // This will break out from the inside.
{
/* Find separator or set pos to end of text */
separatorPos = path.find( "\\", namePos );
if( separatorPos == string::npos )
separatorPos = path.size();
/* Extract tag name and check if it exists */
tagName = path.substr( namePos, separatorPos-namePos );
currentTree = (XMLTree *) currentNode; // It is indeed a tree.
if( !currentTree->containsNode( tagName ) )
return false; // Not found.
currentNode = currentTree->getNode( tagName );
/* Are there more tags in the path? */
if( separatorPos < path.size() )
{
/* Now, the current node better be a tree */
if( currentNode->getType() != xml_subtree )
{
return false; // Not found.
} else
{
namePos = separatorPos + 1; // Advance position in path.
}
} else
{
break; // Found, exit loop.
}
}
return true; // Found!
}
const string & XMLFile::getValue( const string & path )
{
XMLAbstractNode * currentNode = root;
XMLTree * currentTree;
long namePos; // Position for current tag name in path.
long separatorPos; // Position for #-separator following tag name.
string tagName; // Current tag name.
namePos = 0;
while( true ) // This will break out from the inside.
{
/* Find separator or set pos to end of text */
separatorPos = path.find( "\\", namePos );
if( separatorPos == string::npos )
separatorPos = path.size();
/* Extract tag name and check if it exists */
tagName = path.substr( namePos, separatorPos-namePos );
currentTree = (XMLTree *) currentNode; // It is indeed a tree.
if( !currentTree->containsNode( tagName ) )
throw new ErrorMsg( "Node '" + tagName + "' not found!" );
currentNode = currentTree->getNode( tagName );
/* Are there more tags in the path? */
if( separatorPos < path.size() )
{
/* Now, the current node better be a tree */
if( currentNode->getType() != xml_subtree )
{
throw new ErrorMsg( "Illegal path: (" + path + ")!" );
} else
{
namePos = separatorPos + 1; // Advance position in path.
}
} else
{
break; // Found, exit loop.
}
}
/* Check that the current node is an ordinary node */
if( currentNode->getType() != xml_node )
throw new ErrorMsg( "Node '" + tagName + "' is not an element!" );
return ((XMLNode *) currentNode)->getValue();
}
void XMLFile::print()
{
root->print();
}
/* Constructor */
XMLAbstractNode::XMLAbstractNode( const string & _name, XMLNodeType _type ) :
name( _name ),
type( _type )
{
// Node code here.
}
/* Destructor */
XMLAbstractNode::~XMLAbstractNode()
{
// No code here.
}
const string & XMLAbstractNode::getName()
{
return name;
}
XMLNodeType XMLAbstractNode::getType()
{
return type;
}
bool XMLAbstractNode::isName( const string & _name )
{
return (name == _name);
}
/* Constructor */
XMLTree::XMLTree( const string & _name ) :
XMLAbstractNode::XMLAbstractNode( _name, xml_subtree )
{
// No code here.
}
/* Destructor */
XMLTree::~XMLTree()
{
/* Create an iterator for the list */
list<XMLAbstractNode *>::iterator i;
/* Destruct all contained nodes */
for( i = nodes.begin(); i != nodes.end(); i++ )
{
delete (*i);
}
}
void XMLTree::addNode( XMLAbstractNode * newnode )
{
nodes.push_back( newnode );
}
bool XMLTree::containsNode( const string & _name )
{
/* Create an iterator for the list */
list<XMLAbstractNode *>::iterator i;
/* Search for the node with name _name */
i = nodes.begin();
while( i != nodes.end() )
{
if( (*i)->isName( _name ) )
return true;
i++;
}
return false;
}
XMLAbstractNode * XMLTree::getNode( const string & _name )
{
/* Create an iterator for the list */
list<XMLAbstractNode *>::iterator i;
/* Search for the node with name _name */
i = nodes.begin();
while( i != nodes.end() )
{
if( (*i)->isName( _name ) )
return *i;
i++;
}
return NULL;
}
void XMLTree::print()
{
/* Create an iterator for the list */
list<XMLAbstractNode *>::iterator i;
cout << "TREE[ Name: \"" << name << "\" ]:" << endl;
/* Search for the node with name _name */
i = nodes.begin();
while( i != nodes.end() )
{
(*i)->print();
i++;
}
cout << ":END[\"" << name << "\"]" << endl;
}
/* Constructor */
XMLNode::XMLNode( const string & _name, const string & _value ) :
XMLAbstractNode::XMLAbstractNode( _name, xml_node ),
value( _value )
{
// No code here.
}
/* Destructor */
XMLNode::~XMLNode()
{
// Node code here.
}
bool XMLNode::isEmpty()
{
return value.empty();
}
const string & XMLNode::getValue()
{
return value;
}
void XMLNode::print()
{
cout << "NODE[ Name: \"" << name << "\" Value: \"" << value << "\" ]" << endl;
}
/* end of file */
@@ -0,0 +1,65 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : XMLParser.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 3419 $
* Date : $Date: 2008-02-22 09:56:34 +0100 (fr, 22 feb 2008) $
* Updated by : $Author: khole $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A simple XML DOM-like parser. It builds a complete tree from
* the XML file. IT supports <section/> tags, but not tag attributes.
*
*
****************************************************************************/
#ifndef XMLPARSER_HPP
#define XMLPARSER_HPP
using namespace std;
#include "ErrorMsg.hpp"
#include "Utility.hpp"
#include <iostream>
#include <fstream>
#include <list>
class XMLAbstractNode; // Preliminary definitions.
class XMLTree;
class XMLNode;
/* Main XML file class. Contains search methods and entire XML tree */
class XMLFile
{
protected:
XMLTree * root; // The root node, either a subtree or an ordinary node.
void XMLFile::removeStartXML( string & txt ); // Remove the start xml tag.
void removeComments( string & txt ); // Remove comment tags.
void removeAttributes( string & txt ); // Remove attributes from tags.
void readFile( const string & _filename ); // Read XML file.
void parseFragment( string & fragment, XMLTree * parent );
public:
/* Constructors */
XMLFile( const string & _filename );
/* Destructor */
~XMLFile();
/* Methods */
bool exists( const string & path ); // Checks if node exists.
const string & getValue( const string & path ); // Get node value.
void print();
};
#endif
@@ -0,0 +1,47 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : main.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : AVROSP main entry function.
*
*
****************************************************************************/
#include "JobInfo.hpp"
#include <vector>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
JobInfo j;
try
{
j.parseCommandline( argc, argv );
j.doJob();
}
catch( ErrorMsg * e )
{
cout << endl << "An error occurred:" << endl;
cout << " [" << e->What() << "]" << endl;
delete e;
}
return 0;
}
@@ -0,0 +1,3 @@
Made with the free Dev-C++ IDE
http://bloodshed.net/dev/