/************************************************************************/
/* */
/* Bootloader Programmer */
/* Author: Peter Dannegger, danni@specs.de */
/* */
/************************************************************************/
//#define DEBUG
#include <stdio.h>
#include <dos.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <conio.h>
#include <alloc.h>
#include <time.h>
#include "readargs.c"
#define ESCAPE 0xA5
#define COMMAND 0xA6
#define BADCOMMAND 0xA7 // command not supported
#define ANSWER 0xA8 // followed by length byte
#define CONTINUE 0xA9
#define SUCCESS 0xAA
#define FAIL 0xAB
#define PROGEND 0xFF // A5, FF
#define REVISION 0 // get bootloader revision
#define BUFFSIZE 1 // get buffer size
#define SIGNATURE 2 // get target signature
#define USERFLASH 3 // get user flash size
#define PROGRAM 4 // program flash
#define START 5 // start application
#define CHECK_CRC 6 // CRC o.k.
#define VERIFY 7 // Verify
#define TIMEOUTSTART 2
#define TIMEOUT 9 // 0.5s
#define TIMEOUTP 180 // 10s
#define MAXHEX 65535U // max flash size
int ComPort = 0;
unsigned long Baud = 115200L; // 57600L;
char Passwd[130] = "Peda";
char Flash[130] = "";
unsigned int crc;
int buffersize;
long flashsize;
#ifdef DEBUG
FILE *LP;
#endif
void connect( void );
int empfang( int te );
void get_crc( unsigned char d );
void helptext( void );
void initsio( void );
void getpasswd( void );
int octal( char *p );
void program( char *fname, int verify );
int read_crc( void );
int readhex( FILE *fp, unsigned int *addr, unsigned char *data);
void read_info( void );
long readval( void );
void sendbuff( unsigned int len, unsigned char *buff );
void senden(unsigned char c);
void sendcommand(unsigned char c);
void sendstring(unsigned char *text);
int check_crc( int flag );
void main( void )
{
char s[130];
clock_t t;
helptext();
getpasswd();
connect(); // connect ATMega
check_crc( 0 );
read_info();
if( readargs( ASTRING, 'p', &Flash ) ){ // Programming
if( Flash[0] ){
t = clock(); // actual time
program( Flash, 0 );
t = clock() - t;
printf("Elapsed time: %4.2f seconds\n", t / CLK_TCK );
}
}
if( readargs( ASTRING, 'v', &Flash ) ){ // Verify
if( Flash[0] ){
t = clock(); // actual time
program( Flash, 1 );
t = clock() - t;
printf("Elapsed time: %4.2f seconds\n", t / CLK_TCK );
}
}
check_crc( 1 );
getch();
sendcommand( START );
}
int check_crc( int flag )
{
int i;
unsigned int crc1;
sendcommand( CHECK_CRC );
crc1 = crc;
senden( crc1 );
senden( crc1 >> 8 );
i = empfang( TIMEOUT );
switch( i ){
case SUCCESS:
if( flag ) printf("CRC: o.k.\n");
return 0;
case BADCOMMAND:
if( flag ) printf("CRC: not implemented\n");
return 0;
case FAIL:
if( flag ) printf("CRC: error !\n");
default:
return 1;
}
}
void program( char *fname, int verify )
{
FILE *fp;
unsigned int lastaddr = 0;
unsigned int addr;
int i;
unsigned char *data;
unsigned char *dp;
unsigned char s[255];
unsigned char d1;
unsigned long val;
clock_t t = clock();
data = malloc( MAXHEX );
if( data == NULL ){
puts("Memory allocation error !" );
return;
}
memset( data, 0xFF, MAXHEX );
if( NULL == ( fp = fopen( fname, "rb" ) ) ){
printf("File %s open failed !\n", fname);
return;
}
while( (i = readhex( fp, &addr, s )) >= 0 ){
if( i ){
memcpy( data + addr, s, i );
addr += i;
if( lastaddr < addr-1 )
lastaddr = addr-1;
addr++;
}
}
fclose( fp );
if( verify == 0 ){
printf( "Program %s: 0000 - 0000", fname);
sendcommand( PROGRAM );
}else{
sendcommand( VERIFY );
if( empfang( TIMEOUT ) == BADCOMMAND ){
printf("Verify not implemented !\n");
free( data );
return;
}
printf( "Verify %s: 0000 - 0000", fname);
}
for( i = buffersize, addr = 0;; addr++ ){
d1 = data[addr];
senden( d1 );
if( d1 == ESCAPE )
senden( ESCAPE ); // A5,A5 = A5
if( --i == 0 ){
if( clock() - t > 9 ){
t += 9;
printf( "\b\b\b\b%04X", addr + 1 );
}
if( !verify && (i = empfang( TIMEOUTP )) != CONTINUE ){
printf( " failed !" );
break;
}
i = buffersize;
}
if( addr == lastaddr ){
senden( ESCAPE );
senden( PROGEND ); // A5,FF = End
printf( "\b\b\b\b%04X", addr );
if( empfang( TIMEOUTP ) == SUCCESS ){
printf( " successful" );
}else{
printf( " failed !" );
}
break;
}
}
free( data );
printf("\n");
}
int sscanhex( unsigned char *str, unsigned int *hexout, int n )
{
unsigned int hex = 0, x = 0;
for(; n; n--){
x = *str;
if( x >= 'a' )
x += 10 - 'a';
else if( x >= 'A' )
x += 10 - 'A';
else
x -= '0';
if( x >= 16 )
break;
hex = hex * 16 + x;
str++;
}
*hexout = hex;
return n; // 0 if all digits read
}
int readhex( FILE *fp, unsigned int *addr, unsigned char *data){
/* Return value: 1..255 number of bytes
0 end or segment record
-1 file end
-2 error or no HEX-File */
char hexline[524]; // intel hex: max 255 byte
char * hp = hexline;
unsigned int byte;
int i;
unsigned int num;
if( fgets( hexline, 524, fp ) == NULL )
return -1; // end of file
if( *hp++ != ':' )
return -2; // no hex record
if( sscanhex( hp, &num, 2 ))
return -2; // no hex number
hp += 2;
if( sscanhex( hp, addr, 4 ))
return -2;
hp += 4;
if( sscanhex( hp, &byte, 2 ))
return -2;
if( byte != 0 ) // end or segment record
return 0;
for( i = num; i--; ){
hp += 2;
if( sscanhex( hp, &byte, 2 ))
return -2;
*data++ = byte;
}
return num;
}
long readval( void )
{
int i;
int j = 257;
long val = 0;
for(;;){
i = empfang( TIMEOUT );
if( i == -1 )
return -1; // timeout
switch( j ){
case 1:
case 2:
case 3:
val = val * 256 + i;
j--;
break;
case 256:
j = i;
break;
case 257:
if( i == FAIL )
return -2;
if( i == ANSWER )
j = 256;
break;
case 0:
if( i == SUCCESS )
return val;
default:
return -2;
}
}
}
void read_info( void )
{
long i;
char *s = "";
sendcommand( REVISION );
i = readval();
printf("Bootloader V%lX.%lX\n", i>>8, i&0xFF );
sendcommand( SIGNATURE );
i = readval();
switch( i ){
case 0x1e9007: s = "ATtiny13"; break;
case 0x1e910A: s = "ATtiny2313"; break;
case 0x1e9206: s = "ATtiny45"; break;
case 0x1e9307: s = "ATmega8"; break;
case 0x1e9403: s = "ATmega16"; break;
case 0x1e9406: s = "ATmega168"; break;
case 0x1e9502: s = "ATmega32"; break;
case 0x1e9609: s = "ATmega644"; break;
}
printf("Target: %06lX %s\n", i, s );
sendcommand( BUFFSIZE );
i = readval();
buffersize = i;
printf("Buffer: %ld Byte\n", i );
sendcommand( USERFLASH );
i = readval();
flashsize = i;
printf("Size available: %ld Byte\n", i );
}
int octal( char *p ){ // read octals "\123"
int n, i;
if( *p++ != '\\' )
return -1; // no octal number
for( n = 0, i = 3; i; i-- ){
if( *p == 0 )
return -2; // wrong octal number
n = n * 8 + *p++ - '0';
}
return n;
}
void getpasswd( void )
{
char text[81], * t = text, * p = Passwd;
int i, j;
if( readargs( ASTRING, 'i', t ) && *t ){
while( *t ){ // copy string
i = octal( t ); // convert octals
if( i >= 0 ){
*p = i;
t += 3; // octal = 3 bytes
}else{
*p = *t;
}
p++;
t++;
}
*t = 0;
}
}
void connect( void ){
int COM[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
char WAITSTRING[] = { '|', '/', '-', '\\' };
unsigned int i = 1;
readargs( ALONG, 'b', &Baud );
if( Baud < 2 )
Baud = 2;
if( Baud > 115200 )
Baud = 115200;
readargs( AINT, 'c', &i ); // serial port
if( --i > 3 )
i = 0;
printf("COM %d at %ld Baud: ", i+1, Baud );
if( readargs( ABOOL, 'd', &i ) == 0 )
ComPort = COM[i]; // Convert port number to io-address
initsio();
for(;;){
printf( "\b%c", WAITSTRING[++i&3] );
if( kbhit() ){
getch();
printf("\nAborted\n");
exit( 254 );
}
sendstring( Passwd );
if( empfang( 1 ) == SUCCESS ){
printf("\bConnected\n");
crc = 0;
return;
}
}
}
int empfang( int te )
{
unsigned char i;
clock_t t = clock(); // actual time
do{
if( inportb(ComPort+5) & 1 ){ // byte received
i = inportb(ComPort);
return i;
}
}while( (clock() - t ) < te ); // timeout
return -1;
}
void get_crc( unsigned char d )
{
int i;
crc ^= d;
for( i = 8; i; i-- ){
crc = (crc >> 1) ^ ((crc & 1) ? 0xA001 : 0 );
}
}
void helptext( void )
{
int i;
if( readargs( ABOOL, '?', &i ) ){
printf( "/?\t\t Get this help message\n"
"/Bnnnn\t\t Define baud rate\n"
"/Cn\t\t Define serial port n = 1..4\n"
"/PFname,Ename\t Perform Program\n"
"/VFname,Ename\t Perform Verify\n"
// "/RFname,Ename\t Perform Read\n"
"/D\t\t Debug Mode\n"
"Press any Key ! " );
getch();
printf("\n");
exit( 255 );
}
}
void initsio( void )
{
while( (inportb(ComPort+5) & 0x60) != 0x60 ); // Senden beenden
while( (inportb(ComPort+5) & 1) == 1 )
inportb(ComPort); // Empfangspuffer leeren
outportb(ComPort+3, 0x87); // Einlesen Baudrate
outportb(ComPort, (115200 / Baud) & 0xFF ); // Baudrate low
outportb(ComPort+1, 450 / Baud ); // Baudrate high
outportb(ComPort+3, 0x03); // N, 1, 8
outportb(ComPort+1, 0x00); // Interruptsperre
outportb(ComPort+4, 0); // DTR = RTS = 0
}
void senden(unsigned char c)
{
while( (inportb(ComPort+5) & 0x20) == 0); /* Test Sendepuffer leer */
outportb(ComPort, c );
get_crc( c ); // calculate transmit CRC
}
void sendbuff( unsigned int len, unsigned char *buff )
{
while( len-- )
senden( *buff++ );
}
void sendcommand(unsigned char c)
{
senden( COMMAND );
senden( c );
}
void sendstring(unsigned char *text){
while( *text )
senden( *text++ );
}