Move some external files to external/ folder (#744)
It is lot easier to work with automatic formatters if we have external files in different folder. For some tools we can example just exclude external all together. Co-authored-by: Kari Argillander <kari.argillander@fidelix.com>
This commit is contained in:
@@ -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
|
||||
|
||||
+157
@@ -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
|
||||
|
||||
+169
@@ -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
|
||||
|
||||
+364
@@ -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
|
||||
|
||||
+1296
File diff suppressed because it is too large
Load Diff
+105
@@ -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
|
||||
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* 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 > 99 )
|
||||
throw new ErrorMsg( "Only COM1 to COM99 is supported!" );
|
||||
|
||||
/* Initialize internal parameters */
|
||||
portNumber = _portNumber;
|
||||
timeout = _timeout;
|
||||
channelOpen = false;
|
||||
}
|
||||
|
||||
|
||||
/* Destructor */
|
||||
SerialPort::~SerialPort()
|
||||
{
|
||||
closeChannel();
|
||||
}
|
||||
|
||||
|
||||
/* Open the communication channel */
|
||||
void SerialPort::openChannel()
|
||||
{
|
||||
/* CreateFile expects a constant char, or char from the heap */
|
||||
static char comName[64] = "COM1";
|
||||
|
||||
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 */
|
||||
if (portNumber < 10) {
|
||||
comName[3] = '0' + portNumber;
|
||||
} else if (portNumber < 100) {
|
||||
/* For COM ports greater than 9 you have to use a special syntax
|
||||
for CreateFile. The syntax also works for COM ports 1-9. */
|
||||
/* http://support.microsoft.com/kb/115831 */
|
||||
snprintf(comName, sizeof(comName), "\\\\.\\COM%ld", 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
|
||||
|
||||
+181
@@ -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
|
||||
|
||||
+637
@@ -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
|
||||
|
||||
+47
@@ -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/
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
# Hey Emacs, this is a -*- makefile -*-
|
||||
|
||||
# AVR-GCC Makefile template, derived from the WinAVR template (which
|
||||
# is public domain), believed to be neutral to any flavor of "make"
|
||||
# (GNU make, BSD make, SysV make)
|
||||
|
||||
|
||||
MCU = atmega644p
|
||||
FORMAT = ihex
|
||||
TARGET = bootloader
|
||||
SRC = main.c serial.c
|
||||
ASRC =
|
||||
OPT = s
|
||||
BASEADDR = 0xF800
|
||||
|
||||
# Name of this Makefile (used for "make depend").
|
||||
MAKEFILE = Makefile
|
||||
|
||||
# Debugging format.
|
||||
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
|
||||
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
|
||||
DEBUG = stabs
|
||||
|
||||
# Compiler flag to set the C Standard level.
|
||||
# c89 - "ANSI" C
|
||||
# gnu89 - c89 plus GCC extensions
|
||||
# c99 - ISO C99 standard (not yet fully implemented)
|
||||
# gnu99 - c99 plus GCC extensions
|
||||
CSTANDARD = -std=gnu99
|
||||
|
||||
# Place -D or -U options here
|
||||
CDEFS =
|
||||
#CDEFS += -DREMOVE_FLASH_BYTE_SUPPORT
|
||||
#CDEFS += -DREMOVE_EEPROM_BYTE_SUPPORT
|
||||
#CDEFS += -DREMOVE_FUSE_AND_LOCK_BIT_SUPPORT
|
||||
#CDEFS += -DREMOVE_AVRPROG_SUPPORT
|
||||
#CDEFS += -DREMOVE_BLOCK_SUPPORT
|
||||
|
||||
# Place -I options here
|
||||
CINCS =
|
||||
|
||||
|
||||
CDEBUG = -g$(DEBUG)
|
||||
CWARN = -Wall -Wstrict-prototypes
|
||||
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
|
||||
CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CTUNING) $(CEXTRA)
|
||||
|
||||
|
||||
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
|
||||
|
||||
|
||||
#Additional libraries.
|
||||
|
||||
# Minimalistic printf version
|
||||
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
|
||||
|
||||
# Floating point printf version (requires MATH_LIB = -lm below)
|
||||
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
|
||||
|
||||
PRINTF_LIB =
|
||||
|
||||
# Minimalistic scanf version
|
||||
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
|
||||
|
||||
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
|
||||
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
|
||||
|
||||
SCANF_LIB =
|
||||
|
||||
MATH_LIB = -lm
|
||||
|
||||
# External memory options
|
||||
|
||||
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
||||
# used for variables (.data/.bss) and heap (malloc()).
|
||||
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
|
||||
|
||||
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
||||
# only used for heap (malloc()).
|
||||
#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff
|
||||
|
||||
EXTMEMOPTS =
|
||||
|
||||
#LDMAP = $(LDFLAGS) -Wl,-Map=$(TARGET).map,--cref
|
||||
LDFLAGS = -Ttext=$(BASEADDR) $(EXTMEMOPTS) $(LDMAP) $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
|
||||
|
||||
|
||||
# Programming support using avrdude. Settings and variables.
|
||||
# jtag2fast = Atmel JTAG ICE mkII, running at 115200 Bd
|
||||
# jtag2slow = Atmel JTAG ICE mkII, running at 19200 Bd
|
||||
# avrispmkII = AVR ISP MKII
|
||||
#AVRDUDE_PROGRAMMER = jtag2fast
|
||||
AVRDUDE_PROGRAMMER = avrispmkII
|
||||
#AVRDUDE_PROGRAMMER = dragon_isp
|
||||
#AVRDUDE_PROGRAMMER = dragon_jtag
|
||||
#
|
||||
# # port--serial or parallel port to which your
|
||||
# # hardware programmer is attached
|
||||
# # usb can just be usb
|
||||
# # /dev/ttya
|
||||
AVRDUDE_PORT = usb
|
||||
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
|
||||
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
|
||||
|
||||
|
||||
# Uncomment the following if you want avrdude's erase cycle counter.
|
||||
# Note that this counter needs to be initialized first using -Yn,
|
||||
# see avrdude manual.
|
||||
#AVRDUDE_ERASE_COUNTER = -y
|
||||
|
||||
# Uncomment the following if you do /not/ wish a verification to be
|
||||
# performed after programming the device.
|
||||
AVRDUDE_NO_VERIFY = -V
|
||||
|
||||
# Increase verbosity level. Please use this when submitting bug
|
||||
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
|
||||
# to submit bug reports.
|
||||
#AVRDUDE_VERBOSE = -v -v
|
||||
|
||||
# Disable auto-erase so that the chip can be initially
|
||||
# programmed with application code, with the bootloader code added second
|
||||
AVRDUDE_AUTOERASE = -D
|
||||
|
||||
AVRDUDE_BASIC = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
||||
AVRDUDE_FLAGS = $(AVRDUDE_BASIC)
|
||||
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
|
||||
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
|
||||
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
|
||||
AVRDUDE_FLAGS += $(AVRDUDE_AUTOERASE)
|
||||
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
NM = avr-nm
|
||||
AVRDUDE = avrdude
|
||||
REMOVE = rm -f
|
||||
MV = mv -f
|
||||
|
||||
# Define all object files.
|
||||
OBJ = $(SRC:.c=.o) $(ASRC:.S=.o)
|
||||
|
||||
# Define all listing files.
|
||||
LST = $(ASRC:.S=.lst) $(SRC:.c=.lst)
|
||||
|
||||
# Combine all necessary flags and optional flags.
|
||||
# Add target processor to flags.
|
||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
|
||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
# Default target.
|
||||
all: build
|
||||
|
||||
build: elf hex eep
|
||||
|
||||
elf: $(TARGET).elf
|
||||
hex: $(TARGET).hex
|
||||
eep: $(TARGET).eep
|
||||
lss: $(TARGET).lss
|
||||
sym: $(TARGET).sym
|
||||
|
||||
|
||||
# Program the device.
|
||||
install: $(TARGET).hex $(TARGET).eep
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||
COFFCONVERT=$(OBJCOPY) --debugging \
|
||||
--change-section-address .data-0x800000 \
|
||||
--change-section-address .bss-0x800000 \
|
||||
--change-section-address .noinit-0x800000 \
|
||||
--change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
coff: $(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof
|
||||
|
||||
|
||||
extcoff: $(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof
|
||||
|
||||
|
||||
.SUFFIXES: .elf .hex .eep .lss .sym
|
||||
|
||||
.elf.hex:
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
.elf.eep:
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
.elf.lss:
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# Create a symbol table from ELF output file.
|
||||
.elf.sym:
|
||||
$(NM) -n $< > $@
|
||||
|
||||
|
||||
|
||||
# Link: create ELF output file from object files.
|
||||
$(TARGET).elf: $(OBJ)
|
||||
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
|
||||
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
.c.o:
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
.c.s:
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
.S.o:
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
|
||||
# Target: clean project.
|
||||
clean:
|
||||
$(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \
|
||||
$(TARGET).map $(TARGET).sym $(TARGET).lss \
|
||||
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d)
|
||||
|
||||
depend:
|
||||
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
|
||||
then \
|
||||
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
|
||||
$(MAKEFILE).$$$$ && \
|
||||
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
|
||||
fi
|
||||
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
|
||||
>> $(MAKEFILE); \
|
||||
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE)
|
||||
|
||||
.PHONY: all build elf hex eep lss sym program coff extcoff clean depend
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<AVRStudio><MANAGEMENT><ProjectName>bootloader</ProjectName><Created>27-May-2009 06:28:56</Created><LastEdit>27-May-2009 06:28:56</LastEdit><ICON>241</ICON><ProjectType>0</ProjectType><Created>27-May-2009 06:28:56</Created><Version>4</Version><Build>4, 15, 0, 623</Build><ProjectTypeName>AVR GCC</ProjectTypeName></MANAGEMENT><CODE_CREATION><ObjectFile></ObjectFile><EntryFile></EntryFile><SaveFolder>D:\code\bacnet-stack\ports\bdk-atxx4-mstp\bootloader\</SaveFolder></CODE_CREATION><DEBUG_TARGET><CURRENT_TARGET>JTAGICE mkII</CURRENT_TARGET><CURRENT_PART>ATmega644P.xml</CURRENT_PART><BREAKPOINTS></BREAKPOINTS><IO_EXPAND><HIDE>false</HIDE></IO_EXPAND><REGISTERNAMES><Register>R00</Register><Register>R01</Register><Register>R02</Register><Register>R03</Register><Register>R04</Register><Register>R05</Register><Register>R06</Register><Register>R07</Register><Register>R08</Register><Register>R09</Register><Register>R10</Register><Register>R11</Register><Register>R12</Register><Register>R13</Register><Register>R14</Register><Register>R15</Register><Register>R16</Register><Register>R17</Register><Register>R18</Register><Register>R19</Register><Register>R20</Register><Register>R21</Register><Register>R22</Register><Register>R23</Register><Register>R24</Register><Register>R25</Register><Register>R26</Register><Register>R27</Register><Register>R28</Register><Register>R29</Register><Register>R30</Register><Register>R31</Register></REGISTERNAMES><COM>Auto</COM><COMType>0</COMType><WATCHNUM>0</WATCHNUM><WATCHNAMES><Pane0></Pane0><Pane1></Pane1><Pane2></Pane2><Pane3></Pane3></WATCHNAMES><BreakOnTrcaeFull>0</BreakOnTrcaeFull></DEBUG_TARGET><Debugger><Triggers></Triggers></Debugger><AVRGCCPLUGIN><FILES/><CONFIGS><CONFIG><NAME>default</NAME><USESEXTERNALMAKEFILE>NO</USESEXTERNALMAKEFILE><EXTERNALMAKEFILE></EXTERNALMAKEFILE><PART>atmega128</PART><HEX>1</HEX><LIST>1</LIST><MAP>1</MAP><OUTPUTFILENAME>bootloader.elf</OUTPUTFILENAME><OUTPUTDIR>default\</OUTPUTDIR><ISDIRTY>0</ISDIRTY><OPTIONS/><INCDIRS/><LIBDIRS/><LIBS/><LINKOBJECTS/><OPTIONSFORALL>-Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums</OPTIONSFORALL><LINKEROPTIONS></LINKEROPTIONS><SEGMENTS/></CONFIG></CONFIGS><LASTCONFIG>default</LASTCONFIG></AVRGCCPLUGIN><IOView><usergroups/><sort sorted="0" column="0" ordername="1" orderaddress="1" ordergroup="1"/></IOView><Files></Files><Events><Bookmarks></Bookmarks></Events><Trace><Filters></Filters></Trace></AVRStudio>
|
||||
@@ -0,0 +1,58 @@
|
||||
/* definitions generated by preprocessor, copy into defines.h */
|
||||
#ifndef PPINC
|
||||
#define _ATMEGA644P /* device select: _ATMEGAxxxx */
|
||||
#define _B2048 /* boot size select: _Bxxxx (words), powers of two only */
|
||||
#ifdef __ICCAVR__
|
||||
#include "iom644.h"
|
||||
#endif
|
||||
#if __GNUC__
|
||||
#include <avr/io.h>
|
||||
|
||||
#if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 3)
|
||||
|
||||
#if !defined(EEWE) && defined(EEPE)
|
||||
#define EEWE EEPE
|
||||
#endif
|
||||
|
||||
#if !defined(EEMWE) && defined(EEMPE)
|
||||
#define EEMWE EEMPE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* define pin for enter-self-prog-mode */
|
||||
#define PROGPORT PORTB
|
||||
#define PROGPIN PINB
|
||||
#define PROG_NO PB0
|
||||
|
||||
/* baud rate register value calculation */
|
||||
#define CPU_FREQ 18430000
|
||||
#define BAUD_RATE 115200
|
||||
#define BRREG_VALUE 9
|
||||
|
||||
/* definitions for UART control */
|
||||
#define BAUD_RATE_LOW_REG UBRR1
|
||||
#define UART_CONTROL_REG UCSR1B
|
||||
#define ENABLE_TRANSMITTER_BIT TXEN1
|
||||
#define ENABLE_RECEIVER_BIT RXEN1
|
||||
#define UART_STATUS_REG UCSR1A
|
||||
#define TRANSMIT_COMPLETE_BIT TXC1
|
||||
#define RECEIVE_COMPLETE_BIT RXC1
|
||||
#define UART_DATA_REG UDR1
|
||||
|
||||
/* definitions for SPM control */
|
||||
#define SPMCR_REG SPMCSR
|
||||
#define PAGESIZE 256
|
||||
#define APP_END 61440
|
||||
/*#define LARGE_MEMORY */
|
||||
|
||||
/* definitions for device recognition */
|
||||
#define PARTCODE 0
|
||||
#define SIGNATURE_BYTE_1 0x1E
|
||||
#define SIGNATURE_BYTE_2 0x96
|
||||
#define SIGNATURE_BYTE_3 0x0A
|
||||
|
||||
/* indicate that preprocessor result is included */
|
||||
#define PPINC
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Atmel Corporation
|
||||
*
|
||||
* File : flash.h
|
||||
* Compiler : IAR C 3.10C Kickstart, AVR-GCC/avr-libc(>= 1.2.5)
|
||||
* Revision : $Revision: 1.7 $
|
||||
* Date : $Date: Tuesday, June 07, 200 $
|
||||
* Updated by : $Author: raapeland $
|
||||
*
|
||||
* Support mail : avr@atmel.com
|
||||
*
|
||||
* Target platform : All AVRs with bootloader support
|
||||
*
|
||||
* AppNote : AVR109 - Self-programming
|
||||
*
|
||||
* Description : Flash operations for AVR109 Self-programming
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(__ICCAVR__)
|
||||
|
||||
/* IAR Embedded Workbench */
|
||||
#include <inavr.h>
|
||||
|
||||
#define _GET_LOCK_BITS() __AddrToZByteToSPMCR_LPM( (void __flash *) 0x0001, 0x09 )
|
||||
#define _GET_LOW_FUSES() __AddrToZByteToSPMCR_LPM( (void __flash *) 0x0000, 0x09 )
|
||||
#define _GET_HIGH_FUSES() __AddrToZByteToSPMCR_LPM( (void __flash *) 0x0003, 0x09 )
|
||||
#define _GET_EXTENDED_FUSES() __AddrToZByteToSPMCR_LPM( (void __flash *) 0x0002, 0x09 )
|
||||
#define _SET_LOCK_BITS(data) __DataToR0ByteToSPMCR_SPM( data, 0x09 )
|
||||
#define _ENABLE_RWW_SECTION() __DataToR0ByteToSPMCR_SPM( 0x00, 0x11 )
|
||||
|
||||
#define _WAIT_FOR_SPM() while( SPMCR_REG & (1<<SPMEN) );
|
||||
|
||||
#ifndef LARGE_MEMORY
|
||||
#define _LOAD_PROGRAM_MEMORY(addr) __load_program_memory( (const unsigned char __flash *) (addr) )
|
||||
#define _FILL_TEMP_WORD(addr,data) __AddrToZWordToR1R0ByteToSPMCR_SPM( (void __flash *) (addr), data, 0x01 )
|
||||
#define _PAGE_ERASE(addr) __AddrToZByteToSPMCR_SPM( (void __flash *) (addr), 0x03 )
|
||||
#define _PAGE_WRITE(addr) __AddrToZByteToSPMCR_SPM( (void __flash *) (addr), 0x05 )
|
||||
#else /* LARGE_MEMORY */
|
||||
#define _LOAD_PROGRAM_MEMORY(addr) __extended_load_program_memory( (const unsigned char __farflash *) (addr) )
|
||||
#define _FILL_TEMP_WORD(addr,data) __AddrToZ24WordToR1R0ByteToSPMCR_SPM( (void __farflash *) (addr), data, 0x01 )
|
||||
#define _PAGE_ERASE(addr) __AddrToZ24ByteToSPMCR_SPM( (void __farflash *) (addr), 0x03 )
|
||||
#define _PAGE_WRITE(addr) __AddrToZ24ByteToSPMCR_SPM( (void __farflash *) (addr), 0x05 )
|
||||
#endif /* LARGE_MEMORY */
|
||||
|
||||
#elif __GNUC__ > 0
|
||||
|
||||
/* AVR-GCC/avr-libc */
|
||||
#include <avr/boot.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#if defined(GET_LOCK_BITS) /* avr-libc >= 1.2.5 */
|
||||
#define _GET_LOCK_BITS() boot_lock_fuse_bits_get(GET_LOCK_BITS)
|
||||
#define _GET_LOW_FUSES() boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS)
|
||||
#define _GET_HIGH_FUSES() boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS)
|
||||
#define _GET_EXTENDED_FUSES() boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS)
|
||||
#endif /* defined(GET_LOCK_BITS) */
|
||||
#define _SET_LOCK_BITS(data) boot_lock_bits_set(~data)
|
||||
#define _ENABLE_RWW_SECTION() boot_rww_enable()
|
||||
|
||||
#define _WAIT_FOR_SPM() boot_spm_busy_wait()
|
||||
|
||||
#ifndef LARGE_MEMORY
|
||||
#define _LOAD_PROGRAM_MEMORY(addr) pgm_read_byte_near(addr)
|
||||
#else /* LARGE_MEMORY */
|
||||
#define _LOAD_PROGRAM_MEMORY(addr) pgm_read_byte_far(addr)
|
||||
#endif /* LARGE_MEMORY */
|
||||
#define _FILL_TEMP_WORD(addr,data) boot_page_fill(addr, data)
|
||||
#define _PAGE_ERASE(addr) boot_page_erase(addr)
|
||||
#define _PAGE_WRITE(addr) boot_page_write(addr)
|
||||
|
||||
#else
|
||||
#error "Don't know your compiler."
|
||||
#endif
|
||||
+450
@@ -0,0 +1,450 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Atmel Corporation
|
||||
*
|
||||
* File : main.c
|
||||
* Compiler : IAR C 3.10C Kickstart, AVR-GCC/avr-libc(>= 1.2.5)
|
||||
* Revision : $Revision: 1.7 $
|
||||
* Date : $Date: Tuesday, June 07, 200 $
|
||||
* Updated by : $Author: raapeland $
|
||||
*
|
||||
* Support mail : avr@atmel.com
|
||||
*
|
||||
* Target platform : All AVRs with bootloader support
|
||||
*
|
||||
* AppNote : AVR109 - Self-programming
|
||||
*
|
||||
* Description : This Program allows an AVR with bootloader capabilities to
|
||||
* Read/write its own Flash/EEprom. To enter Programming mode
|
||||
* an input pin is checked. If this pin is pulled low,
|
||||
*programming mode is entered. If not, normal execution is done from $0000
|
||||
* "reset" vector in Application area.
|
||||
*
|
||||
* Preparations : Use the preprocessor.xls file for obtaining a customized
|
||||
* defines.h file and linker-file code-segment definition for
|
||||
* the device you are compiling for.
|
||||
****************************************************************************/
|
||||
#include "defines.h"
|
||||
#include "serial.h"
|
||||
#include "flash.h"
|
||||
|
||||
/* Uncomment the following to save code space */
|
||||
/*#define REMOVE_AVRPROG_SUPPORT */
|
||||
/*#define REMOVE_FUSE_AND_LOCK_BIT_SUPPORT */
|
||||
/*#define REMOVE_BLOCK_SUPPORT */
|
||||
/*#define REMOVE_EEPROM_BYTE_SUPPORT */
|
||||
/*#define REMOVE_FLASH_BYTE_SUPPORT */
|
||||
|
||||
/*
|
||||
* GCC doesn't optimize long int arithmetics very clever. As the
|
||||
* address only needs to be larger than 16 bits for the ATmega128 and
|
||||
* above (where flash consumptions isn't much of an issue as the
|
||||
* entire boot loader will still fit even into the smallest possible
|
||||
* boot loader section), save space by using a 16-bit variable for the
|
||||
* smaller devices.
|
||||
*/
|
||||
#ifdef LARGE_MEMORY
|
||||
#define ADDR_T unsigned long
|
||||
#else /* !LARGE_MEMORY */
|
||||
#define ADDR_T unsigned int
|
||||
#endif /* LARGE_MEMORY */
|
||||
|
||||
#ifndef REMOVE_BLOCK_SUPPORT
|
||||
unsigned char BlockLoad(unsigned int size, unsigned char mem, ADDR_T *address);
|
||||
void BlockRead(unsigned int size, unsigned char mem, ADDR_T *address);
|
||||
|
||||
/* BLOCKSIZE should be chosen so that the following holds: BLOCKSIZE*n =
|
||||
* PAGESIZE, where n=1,2,3... */
|
||||
#define BLOCKSIZE PAGESIZE
|
||||
|
||||
#endif /* REMOVE_BLOCK_SUPPORT */
|
||||
|
||||
#ifdef __ICCAVR__
|
||||
__C_task void main(void)
|
||||
#else /* ! __ICCAVR__ */
|
||||
int main(void)
|
||||
#endif /* __ICCAVR__ */
|
||||
{
|
||||
ADDR_T address;
|
||||
unsigned int temp_int;
|
||||
unsigned char val;
|
||||
|
||||
/* Initialization */
|
||||
void (*funcptr)(void) =
|
||||
0x0000; /* Set up function pointer to RESET vector. */
|
||||
PROGPORT |=
|
||||
(1 << PROG_NO); /* Enable pull-up on PROG_NO line on PROGPORT. */
|
||||
initbootuart(); /* Initialize UART. */
|
||||
|
||||
/* Branch to bootloader or application code? */
|
||||
if (!(PROGPIN & (1 << PROG_NO))) { /* If PROGPIN is pulled low, enter
|
||||
programmingmode. */
|
||||
/* Main loop */
|
||||
for (;;) {
|
||||
val = recchar(); /* Wait for command character. */
|
||||
|
||||
/* Check autoincrement status. */
|
||||
if (val == 'a') {
|
||||
sendchar('Y'); /* Yes, we do autoincrement. */
|
||||
}
|
||||
|
||||
/* Set address. */
|
||||
else if (val == 'A') {
|
||||
/* Set address... */ /* NOTE: Flash addresses are given in
|
||||
words, not bytes. */
|
||||
address = (recchar() << 8) |
|
||||
recchar(); /* Read address high and low byte. */
|
||||
sendchar('\r'); /* Send OK back. */
|
||||
}
|
||||
|
||||
/* Chip erase. */
|
||||
else if (val == 'e') {
|
||||
for (address = 0; address < APP_END; address +=
|
||||
PAGESIZE) { /* NOTE: Here we use address as a byte-address,
|
||||
not word-address, for convenience. */
|
||||
_WAIT_FOR_SPM();
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_suppress = Pe1053 /* Suppress warning for conversion from \
|
||||
long-type address to flash ptr. */
|
||||
#endif
|
||||
_PAGE_ERASE(address);
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_default = Pe1053 /* Back to default. */
|
||||
#endif
|
||||
}
|
||||
|
||||
sendchar('\r'); /* Send OK back. */
|
||||
}
|
||||
#ifndef REMOVE_BLOCK_SUPPORT
|
||||
/* Check block load support. */
|
||||
else if (val == 'b') {
|
||||
sendchar('Y'); /* Report block load supported. */
|
||||
sendchar((BLOCKSIZE >> 8) & 0xFF); /* MSB first. */
|
||||
sendchar(BLOCKSIZE & 0xFF); /* Report BLOCKSIZE (bytes). */
|
||||
}
|
||||
|
||||
/* Start block load. */
|
||||
else if (val == 'B') {
|
||||
temp_int = (recchar() << 8) | recchar(); /* Get block size. */
|
||||
val = recchar(); /* Get memtype. */
|
||||
sendchar(BlockLoad(temp_int, val, &address)); /* Block load. */
|
||||
}
|
||||
|
||||
/* Start block read. */
|
||||
else if (val == 'g') {
|
||||
temp_int = (recchar() << 8) | recchar(); /* Get block size. */
|
||||
val = recchar(); /* Get memtype */
|
||||
BlockRead(temp_int, val, &address); /* Block read */
|
||||
}
|
||||
#endif /* REMOVE_BLOCK_SUPPORT */
|
||||
|
||||
#ifndef REMOVE_FLASH_BYTE_SUPPORT
|
||||
/* Read program memory. */
|
||||
else if (val == 'R') {
|
||||
/* Send high byte, then low byte of flash word. */
|
||||
_WAIT_FOR_SPM();
|
||||
_ENABLE_RWW_SECTION();
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_suppress = Pe1053 /* Suppress warning for conversion from \
|
||||
long-type address to flash ptr. */
|
||||
#endif
|
||||
sendchar(_LOAD_PROGRAM_MEMORY((address << 1) + 1));
|
||||
sendchar(_LOAD_PROGRAM_MEMORY((address << 1) + 0));
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_default = Pe1053 /* Back to default. */
|
||||
#endif
|
||||
|
||||
address++; /* Auto-advance to next Flash word. */
|
||||
}
|
||||
|
||||
/* Write program memory, low byte. */
|
||||
else if (val == 'c') { /* NOTE: Always use this command before
|
||||
sending high byte. */
|
||||
temp_int =
|
||||
recchar(); /* Get low byte for later _FILL_TEMP_WORD. */
|
||||
sendchar('\r'); /* Send OK back. */
|
||||
}
|
||||
|
||||
/* Write program memory, high byte. */
|
||||
else if (val == 'C') {
|
||||
temp_int |= (recchar() << 8); /* Get and insert high byte. */
|
||||
_WAIT_FOR_SPM();
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_suppress = Pe1053 /* Suppress warning for conversion from \
|
||||
long-type address to flash ptr. */
|
||||
#endif
|
||||
_FILL_TEMP_WORD(
|
||||
(address << 1), temp_int); /* Convert word-address to
|
||||
byte-address and fill. */
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_default = Pe1053 /* Back to default. */
|
||||
#endif
|
||||
address++; /* Auto-advance to next Flash word. */
|
||||
sendchar('\r'); /* Send OK back. */
|
||||
}
|
||||
|
||||
/* Write page. */
|
||||
else if (val == 'm') {
|
||||
if (address >= (APP_END >> 1)) { /* Protect bootloader area. */
|
||||
sendchar('?');
|
||||
} else {
|
||||
_WAIT_FOR_SPM();
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_suppress = Pe1053 /* Suppress warning for conversion from \
|
||||
long-type address to flash ptr. */
|
||||
#endif
|
||||
_PAGE_WRITE(address << 1); /* Convert word-address to
|
||||
byte-address and write. */
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_default = Pe1053 /* Back to default. */
|
||||
#endif
|
||||
}
|
||||
|
||||
sendchar('\r'); /* Send OK back. */
|
||||
}
|
||||
#endif /* REMOVE_FLASH_BYTE_SUPPORT */
|
||||
|
||||
#ifndef REMOVE_EEPROM_BYTE_SUPPORT
|
||||
/* Write EEPROM memory. */
|
||||
else if (val == 'D') {
|
||||
_WAIT_FOR_SPM();
|
||||
EEARL = address; /* Setup EEPROM address. */
|
||||
EEARH = (address >> 8);
|
||||
EEDR = recchar(); /* Get byte. */
|
||||
EECR |= (1 << EEMWE); /* Write byte. */
|
||||
EECR |= (1 << EEWE);
|
||||
while (EECR &
|
||||
(1 << EEWE)) /* Wait for write operation to finish. */
|
||||
;
|
||||
|
||||
address++; /* Auto-advance to next EEPROM byte. */
|
||||
sendchar('\r'); /* Send OK back. */
|
||||
}
|
||||
|
||||
/* Read EEPROM memory. */
|
||||
else if (val == 'd') {
|
||||
EEARL = address; /* Setup EEPROM address. */
|
||||
EEARH = (address >> 8);
|
||||
EECR |= (1 << EERE); /* Read byte... */
|
||||
sendchar(EEDR); /* ...and send it back. */
|
||||
address++; /* Auto-advance to next EEPROM byte. */
|
||||
}
|
||||
#endif /* REMOVE_EEPROM_BYTE_SUPPORT */
|
||||
|
||||
#ifndef REMOVE_FUSE_AND_LOCK_BIT_SUPPORT
|
||||
/* Write lockbits. */
|
||||
else if (val == 'l') {
|
||||
_WAIT_FOR_SPM();
|
||||
_SET_LOCK_BITS(recchar()); /* Read and set lock bits. */
|
||||
sendchar('\r'); /* Send OK back. */
|
||||
}
|
||||
#if defined(_GET_LOCK_BITS)
|
||||
/* Read lock bits. */
|
||||
else if (val == 'r') {
|
||||
_WAIT_FOR_SPM();
|
||||
sendchar(_GET_LOCK_BITS());
|
||||
}
|
||||
|
||||
/* Read fuse bits. */
|
||||
else if (val == 'F') {
|
||||
_WAIT_FOR_SPM();
|
||||
sendchar(_GET_LOW_FUSES());
|
||||
}
|
||||
|
||||
/* Read high fuse bits. */
|
||||
else if (val == 'N') {
|
||||
_WAIT_FOR_SPM();
|
||||
sendchar(_GET_HIGH_FUSES());
|
||||
}
|
||||
|
||||
/* Read extended fuse bits. */
|
||||
else if (val == 'Q') {
|
||||
_WAIT_FOR_SPM();
|
||||
sendchar(_GET_EXTENDED_FUSES());
|
||||
}
|
||||
#endif /* defined(_GET_LOCK_BITS) */
|
||||
#endif /* REMOVE_FUSE_AND_LOCK_BIT_SUPPORT */
|
||||
|
||||
#ifndef REMOVE_AVRPROG_SUPPORT
|
||||
/* Enter and leave programming mode. */
|
||||
else if ((val == 'P') || (val == 'L')) {
|
||||
sendchar('\r'); /* Nothing special to do, just answer OK. */
|
||||
}
|
||||
|
||||
/* Exit bootloader. */
|
||||
else if (val == 'E') {
|
||||
_WAIT_FOR_SPM();
|
||||
_ENABLE_RWW_SECTION();
|
||||
sendchar('\r');
|
||||
funcptr(); /* Jump to Reset vector 0x0000 in Application
|
||||
Section. */
|
||||
}
|
||||
|
||||
/* Get programmer type. */
|
||||
else if (val == 'p') {
|
||||
sendchar('S'); /* Answer 'SERIAL'. */
|
||||
}
|
||||
|
||||
/* Return supported device codes. */
|
||||
else if (val == 't') {
|
||||
#if PARTCODE + 0 > 0
|
||||
sendchar(PARTCODE); /* Supports only this device, of course. */
|
||||
#endif /* PARTCODE */
|
||||
sendchar(0); /* Send list terminator. */
|
||||
}
|
||||
|
||||
/* Set LED, clear LED and set device type. */
|
||||
else if ((val == 'x') || (val == 'y') || (val == 'T')) {
|
||||
recchar(); /* Ignore the command and it's parameter. */
|
||||
sendchar('\r'); /* Send OK back. */
|
||||
}
|
||||
#endif /* REMOVE_AVRPROG_SUPPORT */
|
||||
|
||||
/* Return programmer identifier. */
|
||||
else if (val == 'S') {
|
||||
sendchar('A'); /* Return 'AVRBOOT'. */
|
||||
sendchar('V'); /* Software identifier (aka programmer signature)
|
||||
is always 7 characters. */
|
||||
sendchar('R');
|
||||
sendchar('B');
|
||||
sendchar('O');
|
||||
sendchar('O');
|
||||
sendchar('T');
|
||||
}
|
||||
|
||||
/* Return software version. */
|
||||
else if (val == 'V') {
|
||||
sendchar('1');
|
||||
sendchar('5');
|
||||
}
|
||||
|
||||
/* Return signature bytes. */
|
||||
else if (val == 's') {
|
||||
sendchar(SIGNATURE_BYTE_3);
|
||||
sendchar(SIGNATURE_BYTE_2);
|
||||
sendchar(SIGNATURE_BYTE_1);
|
||||
}
|
||||
|
||||
/* The last command to accept is ESC (synchronization). */
|
||||
else if (val != 0x1b) { /* If not ESC, then it is unrecognized... */
|
||||
sendchar('?');
|
||||
}
|
||||
} /* end: for(;;) */
|
||||
} else {
|
||||
_WAIT_FOR_SPM();
|
||||
_ENABLE_RWW_SECTION();
|
||||
funcptr(); /* Jump to Reset vector 0x0000 in Application Section. */
|
||||
}
|
||||
} /* end: main */
|
||||
|
||||
#ifndef REMOVE_BLOCK_SUPPORT
|
||||
unsigned char BlockLoad(unsigned int size, unsigned char mem, ADDR_T *address)
|
||||
{
|
||||
unsigned char buffer[BLOCKSIZE];
|
||||
unsigned int data;
|
||||
ADDR_T tempaddress;
|
||||
|
||||
/* EEPROM memory type. */
|
||||
if (mem == 'E') {
|
||||
/* Fill buffer first, as EEPROM is too slow to copy with UART speed */
|
||||
for (tempaddress = 0; tempaddress < size; tempaddress++)
|
||||
buffer[tempaddress] = recchar();
|
||||
|
||||
/* Then program the EEPROM */
|
||||
_WAIT_FOR_SPM();
|
||||
for (tempaddress = 0; tempaddress < size; tempaddress++) {
|
||||
EEARL = *address; /* Setup EEPROM address */
|
||||
EEARH = ((*address) >> 8);
|
||||
EEDR = buffer[tempaddress]; /* Get byte. */
|
||||
EECR |= (1 << EEMWE); /* Write byte. */
|
||||
EECR |= (1 << EEWE);
|
||||
while (EECR & (1 << EEWE)) /* Wait for write operation to finish. */
|
||||
;
|
||||
|
||||
(*address)++; /* Select next EEPROM byte */
|
||||
}
|
||||
|
||||
return '\r'; /* Report programming OK */
|
||||
}
|
||||
|
||||
/* Flash memory type. */
|
||||
else if (mem ==
|
||||
'F') { /* NOTE: For flash programming, 'address' is given in words. */
|
||||
(*address) <<= 1; /* Convert address to bytes temporarily. */
|
||||
tempaddress = (*address); /* Store address in page. */
|
||||
|
||||
do {
|
||||
data = recchar();
|
||||
data |= (recchar() << 8);
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_suppress = Pe1053 /* Suppress warning for conversion from \
|
||||
long-type address to flash ptr. */
|
||||
#endif
|
||||
_FILL_TEMP_WORD(*address, data);
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_default = Pe1053 /* Back to default. */
|
||||
#endif
|
||||
(*address) += 2; /* Select next word in memory. */
|
||||
size -= 2; /* Reduce number of bytes to write by two. */
|
||||
} while (size); /* Loop until all bytes written. */
|
||||
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_suppress = Pe1053 /* Suppress warning for conversion from \
|
||||
long-type address to flash ptr. */
|
||||
#endif
|
||||
_PAGE_WRITE(tempaddress);
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_default = Pe1053 /* Back to default. */
|
||||
#endif
|
||||
_WAIT_FOR_SPM();
|
||||
_ENABLE_RWW_SECTION();
|
||||
|
||||
(*address) >>= 1; /* Convert address back to Flash words again. */
|
||||
return '\r'; /* Report programming OK */
|
||||
}
|
||||
|
||||
/* Invalid memory type? */
|
||||
else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
void BlockRead(unsigned int size, unsigned char mem, ADDR_T *address)
|
||||
{
|
||||
/* EEPROM memory type. */
|
||||
if (mem == 'E') { /* Read EEPROM */
|
||||
do {
|
||||
EEARL = *address; /* Setup EEPROM address */
|
||||
EEARH = ((*address) >> 8);
|
||||
(*address)++; /* Select next EEPROM byte */
|
||||
EECR |= (1 << EERE); /* Read EEPROM */
|
||||
sendchar(EEDR); /* Transmit EEPROM dat ato PC */
|
||||
|
||||
size--; /* Decrease number of bytes to read */
|
||||
} while (size); /* Repeat until all block has been read */
|
||||
}
|
||||
|
||||
/* Flash memory type. */
|
||||
else if (mem == 'F') {
|
||||
(*address) <<= 1; /* Convert address to bytes temporarily. */
|
||||
|
||||
do {
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_suppress = Pe1053 /* Suppress warning for conversion from \
|
||||
long-type address to flash ptr. */
|
||||
#endif
|
||||
sendchar(_LOAD_PROGRAM_MEMORY(*address));
|
||||
sendchar(_LOAD_PROGRAM_MEMORY((*address) + 1));
|
||||
#ifdef __ICCAVR__
|
||||
#pragma diag_default = Pe1053 /* Back to default. */
|
||||
#endif
|
||||
(*address) += 2; /* Select next word in memory. */
|
||||
size -= 2; /* Subtract two bytes from number of bytes to read */
|
||||
} while (size); /* Repeat until all block has been read */
|
||||
|
||||
(*address) >>= 1; /* Convert address back to Flash words again. */
|
||||
}
|
||||
}
|
||||
#endif /* REMOVE_BLOCK_SUPPORT */
|
||||
|
||||
/* end of file */
|
||||
@@ -0,0 +1,24 @@
|
||||
#Extracted from "Part definitions" of preprocessor.xls
|
||||
#dev include pagesz nrwwpag totpag avr910 sig1 sig2 sig3 baudlo uartc uarts txen rxen txc rxc udr spmcr
|
||||
ATmega8 iom8.h 32 32 128 0x77 0x1E 0x93 0x07 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
|
||||
ATmega8515 iom8515.h 32 32 128 0x3B 0x1E 0x93 0x06 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
|
||||
ATmega8535 iom8535.h 32 32 128 0x6A 0x1E 0x93 0x08 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
|
||||
ATmega88 iom88.h 32 32 128 0x1E 0x93 0x0A UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCSR
|
||||
ATmega16 iom16.h 64 16 128 0x75 0x1E 0x94 0x03 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
|
||||
ATmega162 iom162.h 64 16 128 0x63 0x1E 0x94 0x04 UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCR
|
||||
ATmega163 iom163.h 64 16 128 0x66 0x1E 0x94 0x02 UBRRLO UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
|
||||
ATmega165 iom165.h 64 16 128 0x1E 0x94 0x07 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCSR
|
||||
ATmega168 iom168.h 64 16 128 0x1E 0x94 0x06 UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCSR
|
||||
ATmega169 iom169.h 64 16 128 0x79 0x1E 0x94 0x05 UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCSR
|
||||
ATmega32 iom32.h 64 32 256 0x7F 0x1E 0x95 0x02 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
|
||||
ATmega323 iom323.h 64 16 256 0x73 0x1E 0x95 0x01 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
|
||||
ATmega329 iom329.h 64 32 256 0x1E 0x95 0x03 UBRR UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCSR
|
||||
ATmega3290 iom3290.h 64 32 256 0x1E 0x95 0x04 UBRR UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCSR
|
||||
ATmega64 iom64.h 128 32 256 0x46 0x1E 0x96 0x02 UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCR
|
||||
ATmega644 iom644.h 128 32 256 0x1E 0x96 0x09 UBRR0 UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCSR
|
||||
ATmega644P iom644.h 128 32 256 0x1E 0x96 0x0A UBRR1 UCSR1B UCSR1A TXEN1 RXEN1 TXC1 RXC1 UDR1 SPMCSR
|
||||
ATmega649 iom649.h 128 32 256 0x1E 0x96 0x03 UBRR UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCSR
|
||||
ATmega6490 iom6490.h 128 32 256 0x1E 0x96 0x04 UBRR UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCSR
|
||||
ATmega128 iom128.h 128 32 512 0x44 0x1E 0x97 0x02 UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCSR
|
||||
ATmega128_1 iom128.h 128 32 512 0x44 0x1E 0x97 0x02 UBRR1L UCSR1B UCSR1A TXEN1 RXEN1 TXC1 RXC1 UDR1 SPMCSR
|
||||
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Equivalent script to what preprocessor.xls might do.
|
||||
#
|
||||
# Run e.g. like
|
||||
# sh preprocessor.sh ATmega128 4096 PORTD PD4 3686400 9600 > defines.h
|
||||
#
|
||||
# Written by Joerg Wunsch, 2005-07-29
|
||||
|
||||
PARTFILE=parts.txt
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "usage: preprocessor.sh device bootsize progport prog_no cpu_freq baud_rate" >& 2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ $# -ne 6 ]
|
||||
then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ ! -f ${PARTFILE} ]
|
||||
then
|
||||
echo "part definition file ${PARTFILE} not found" >& 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
device="$1"
|
||||
bootsize="$2"
|
||||
progport="$3"
|
||||
prog_no="$4"
|
||||
cpu_freq="$5"
|
||||
baud_rate="$6"
|
||||
|
||||
# is there a device at all?
|
||||
if grep -i "^${device} " ${PARTFILE} >/dev/null
|
||||
then
|
||||
:
|
||||
else
|
||||
echo "device ${device} not found in ${PARTFILE}" >& 2
|
||||
exit 1
|
||||
fi
|
||||
devupper=`echo $device | tr '[a-z]' '[A-Z]'`
|
||||
|
||||
# find an awk to use, out of nawk, gawk, or awk
|
||||
AWK=none
|
||||
for name in nawk gawk awk
|
||||
do
|
||||
set -- `type $name 2>/dev/null`
|
||||
if [ "x$2" = 'xis' ]
|
||||
then
|
||||
AWK=$name
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ $AWK = 'none' ]
|
||||
then
|
||||
echo "Sorry, no useable awk found" >& 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# OK, now get the individual fields. Unfortunately, the AVR910 device ID
|
||||
# is optional, and the shell cannot parse that natively. Use awk to
|
||||
# re-order the fields, and sort the avr910 column last (so we'll get an
|
||||
# empty variable in read if it is not present).
|
||||
set -- `grep -i "^${device} " ${PARTFILE} |\
|
||||
${AWK} -F ' ' \
|
||||
'{print $1 " " $2 " " $3 " " $4 " " $5 " " $7 " " $8 " " $9 " " $10 " " $11 " " $12 " " $13 " " $14 " " $15 " " $16 " " $17 " " $18 " " $6; exit}'`
|
||||
dev=$1
|
||||
include=$2
|
||||
pagesz=$3
|
||||
nrwwpag=$4
|
||||
totpag=$5
|
||||
sig1=$6
|
||||
sig2=$7
|
||||
sig3=$8
|
||||
baudlo=$9
|
||||
shift 9
|
||||
uartc=$1
|
||||
uarts=$2
|
||||
txen=$3
|
||||
rxen=$4
|
||||
txc=$5
|
||||
rxc=$6
|
||||
udr=$7
|
||||
spmcr=$8
|
||||
avr910=$9
|
||||
|
||||
# Verify boot size
|
||||
pagebytes=`expr $pagesz \* 2`
|
||||
maxboot=`expr $nrwwpag \* $pagebytes`
|
||||
bootbytes=`expr 2 \* $bootsize` || exit 1
|
||||
if [ \( $bootbytes -ne $maxboot \) -a \
|
||||
\( $bootbytes -ne `expr $maxboot / 4` \) -a \
|
||||
\( $bootbytes -ne `expr $maxboot / 2` \) -a \
|
||||
\( $bootbytes -ne `expr $maxboot \* 3 / 4` \) ]
|
||||
then
|
||||
echo "Invalid boot size ${bootsize}, valid: `expr $maxboot / 8`, `expr $maxboot / 4`, `expr $maxboot \* 3 / 8`, `expr $maxboot / 2` words" >& 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if p=`expr $progport : 'PORT\(.\)'`
|
||||
then
|
||||
: # ok
|
||||
else
|
||||
echo "Invalid port name ${progport}, must be PORTx" >& 2
|
||||
exit 1
|
||||
fi
|
||||
progpin="PIN$p"
|
||||
|
||||
brreg=`expr $cpu_freq / \( 16 \* $baud_rate \) - 1` || exit 1
|
||||
memsize=`expr $totpag \* $pagebytes`
|
||||
append=`expr $memsize - $bootbytes`
|
||||
|
||||
echo "/* definitions generated by preprocessor, copy into defines.h */
|
||||
#ifndef PPINC
|
||||
#define _${devupper} // device select: _ATMEGAxxxx
|
||||
#define _B${bootsize} // boot size select: _Bxxxx (words), powers of two only
|
||||
#ifdef __ICCAVR__
|
||||
#include \"${include}\"
|
||||
#endif
|
||||
#if __GNUC__
|
||||
#include <avr/io.h>
|
||||
#endif
|
||||
|
||||
/* define pin for enter-self-prog-mode */
|
||||
#define PROGPORT ${progport}
|
||||
#define PROGPIN ${progpin}
|
||||
#define PROG_NO ${prog_no}
|
||||
|
||||
/* baud rate register value calculation */
|
||||
#define CPU_FREQ ${cpu_freq}
|
||||
#define BAUD_RATE ${baud_rate}
|
||||
#define BRREG_VALUE ${brreg}
|
||||
|
||||
/* definitions for UART control */
|
||||
#define BAUD_RATE_LOW_REG ${baudlo}
|
||||
#define UART_CONTROL_REG ${uartc}
|
||||
#define ENABLE_TRANSMITTER_BIT ${txen}
|
||||
#define ENABLE_RECEIVER_BIT ${rxen}
|
||||
#define UART_STATUS_REG ${uarts}
|
||||
#define TRANSMIT_COMPLETE_BIT ${txc}
|
||||
#define RECEIVE_COMPLETE_BIT ${rxc}
|
||||
#define UART_DATA_REG ${udr}
|
||||
|
||||
/* definitions for SPM control */
|
||||
#define SPMCR_REG ${spmcr}
|
||||
#define PAGESIZE ${pagebytes}
|
||||
#define APP_END ${append}"
|
||||
|
||||
if [ $memsize -gt 65536 ]
|
||||
then
|
||||
echo "#define LARGE_MEMORY"
|
||||
else
|
||||
echo "//#define LARGE_MEMORY"
|
||||
fi
|
||||
|
||||
echo "
|
||||
/* definitions for device recognition */
|
||||
#define PARTCODE ${avr910}
|
||||
#define SIGNATURE_BYTE_1 ${sig1}
|
||||
#define SIGNATURE_BYTE_2 ${sig2}
|
||||
#define SIGNATURE_BYTE_3 ${sig3}
|
||||
|
||||
/* indicate that preprocessor result is included */
|
||||
#define PPINC
|
||||
#endif"
|
||||
|
||||
echo "(IAR) Replace all code segment definitions in the linker file with the following line:" >& 2
|
||||
${AWK} 'BEGIN {printf "-Z(CODE)INTVEC,FAR_F,SWITCH,CODE=%X-%X\n", '$append', '$memsize' - 1; exit}' >& 2
|
||||
Binary file not shown.
@@ -0,0 +1,41 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Atmel Corporation
|
||||
*
|
||||
* File : serial.c
|
||||
* Compiler : IAR C 3.10C Kickstart, AVR-GCC/avr-libc(>= 1.2.5)
|
||||
* Revision : $Revision: 1.7 $
|
||||
* Date : $Date: Tuesday, June 07, 200 $
|
||||
* Updated by : $Author: raapeland $
|
||||
*
|
||||
* Support mail : avr@atmel.com
|
||||
*
|
||||
* Target platform : All AVRs with bootloader support
|
||||
*
|
||||
* AppNote : AVR109 - Self-programming
|
||||
*
|
||||
* Description : UART communication routines
|
||||
****************************************************************************/
|
||||
#include "defines.h"
|
||||
|
||||
void initbootuart(void)
|
||||
{
|
||||
BAUD_RATE_LOW_REG = BRREG_VALUE;
|
||||
UART_CONTROL_REG = (1 << ENABLE_RECEIVER_BIT) |
|
||||
(1 << ENABLE_TRANSMITTER_BIT); /* enable receive and transmit */
|
||||
}
|
||||
|
||||
void sendchar(unsigned char c)
|
||||
{
|
||||
UART_DATA_REG = c; /* prepare transmission */
|
||||
while (!(UART_STATUS_REG & (1 << TRANSMIT_COMPLETE_BIT)))
|
||||
; /* wait until byte sendt */
|
||||
UART_STATUS_REG |= (1 << TRANSMIT_COMPLETE_BIT); /* delete TXCflag */
|
||||
}
|
||||
|
||||
unsigned char recchar(void)
|
||||
{
|
||||
while (!(UART_STATUS_REG & (1 << RECEIVE_COMPLETE_BIT)))
|
||||
; /* wait for data */
|
||||
return UART_DATA_REG;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Atmel Corporation
|
||||
*
|
||||
* File : serial.h
|
||||
* Compiler : IAR C 3.10C Kickstart, AVR-GCC/avr-libc(>= 1.2.5)
|
||||
* Revision : $Revision: 1.7 $
|
||||
* Date : $Date: Tuesday, June 07, 200 $
|
||||
* Updated by : $Author: raapeland $
|
||||
*
|
||||
* Support mail : avr@atmel.com
|
||||
*
|
||||
* Target platform : All AVRs with bootloader support
|
||||
*
|
||||
* AppNote : AVR109 - Self-programming
|
||||
*
|
||||
* Description : Header file for serial.c
|
||||
****************************************************************************/
|
||||
|
||||
void initbootuart(
|
||||
void);
|
||||
void sendchar(
|
||||
unsigned char);
|
||||
unsigned char recchar(
|
||||
void);
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef STDBOOL_H
|
||||
#define STDBOOL_H
|
||||
|
||||
/* C99 Boolean types for compilers without C99 support */
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef char _Bool;
|
||||
#ifndef bool
|
||||
#define bool _Bool
|
||||
#endif
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user