⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fboot.c

📁 供AVR的ATiny及ATmega系列单片机使用的bootloader
💻 C
字号:
/************************************************************************/
/*									*/
/*			Bootloader Programmer				*/
/*		Author: Peter Dannegger, danni@alice-dsl.net		*/
/*									*/
/************************************************************************/

#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 "protocol.h"
#include "readargs.c"

#define	EXIT_SUCCESS	0
#define	EXIT_ERROR	1
#define	EXIT_ABORT	2

#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 TIMEOUT	        5	// 0.3s
#define TIMEOUTP	72	// 4s
#define STARTWAIT	3

#define	MAXFLASH	0x40000UL	// max flash size (256kB)


int ComPort = 0;
unsigned long Baud = 115200L;		// 57600L;
char Passwd[130] = "Peda";
char Flash[130] = "";

unsigned int crc;
int buffersize;
int echocount = 0;
long flashsize;
unsigned char far *data = NULL;


int connect( void );
int empfang( int te );
void get_crc( unsigned char d );
int helptext( void );
void initsio( void );
void getpasswd( void );
int octal( char *p );
int program( char *fname, int verify );
int read_crc( void );
int readhex( FILE *fp, unsigned long *addr, unsigned char *data);
int 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 sendpwd(unsigned char *text);
int check_crc( void );
void  my_exit( char *msg, int exitcode );


void main( void )
{
  char s[130];
  clock_t t;
  int crc_on;
  unsigned int i;

  if( helptext() )
    exit( EXIT_ABORT );

  getpasswd();
  if( connect() )				// connect ATMega
    my_exit( "\nAborted", EXIT_ABORT);

  crc_on = check_crc();				// 2 = no CRC support
  if( read_info() )
    my_exit( "Error, wrong device informations", EXIT_ERROR );

  if( crc_on != 2 && check_crc() )
    my_exit( "CRC-Error", EXIT_ERROR );

  data = farmalloc( flashsize );
  if( data == NULL )
    my_exit("Memory allocation error !", EXIT_ERROR );

  t = clock();					// actual time
  if( readargs( ASTRING, 'p', &Flash ) ){       // Programming
    if( Flash[0] ){
      if( program( Flash, 0 ))
	my_exit( "Program-Error", EXIT_ERROR );
    }
  }
  if( readargs( ASTRING, 'v', &Flash ) ){       // Verify
    if( Flash[0] ){
      if( program( Flash, 1 ))
	my_exit( "Verify-Error", EXIT_ERROR );
    }
  }
  if( crc_on != 2 ){
    if( check_crc() )
      my_exit( "CRC-Error", EXIT_ERROR );

    printf("CRC: o.k.\n");
  }

  t = clock() - t;
  printf("Elapsed time: %4.2f seconds\n", t / CLK_TCK );

//  getch();
  my_exit( "", EXIT_SUCCESS );
}


void  my_exit( char *msg, int exitcode )
{
  clock_t t;

  sendcommand( PROGEND );
  sendcommand( COMMAND );
  sendcommand( START );
  if( data )
    farfree( data );
  printf( "%s\n", msg );
  for( t = clock(); clock() - t < STARTWAIT; );
  exit( exitcode );
}


int check_crc( void )
{
  unsigned int crc1;

  sendcommand( CHECK_CRC );
  if( empfang( TIMEOUT ) == BADCOMMAND )
    return 2;
  crc1 = crc;
  senden( crc1 );
  senden( crc1 >> 8 );
  if( empfang( TIMEOUT ) == SUCCESS )
    return 0;
  return 1;
}


void far_memset( unsigned char far *dst, unsigned char val, unsigned long size )
{
  while( size > 0x8000 ){
    _fmemset( dst, val, 0x8000 );
    dst = MK_FP( FP_SEG(dst) + 0x800, FP_OFF(dst));
    size -= 0x8000;
  }
  _fmemset( dst, val, size );
}


void far_copy( unsigned char far *dst, unsigned long idx, unsigned char *src, unsigned int len )
{
  unsigned int seg;

  idx += FP_OFF( dst );
  seg = FP_SEG(dst) + (idx>>4);

  _fmemcpy( MK_FP( seg, idx & 0x0F ), src, len );
}


unsigned char far_byte( unsigned char far *src, unsigned long idx )
{
  unsigned int seg;

  idx += FP_OFF(src);
  seg = FP_SEG(src) + (idx>>4);

  return *(unsigned char far *)MK_FP( seg, idx & 0x0F );
}


int program( char *fname, int verify )
{
  FILE *fp;
  unsigned long lastaddr = 0;
  unsigned long addr = 0;
  int i;
  unsigned char s[255];
  unsigned char d1;

  far_memset( data, 0xFF, flashsize );
  if( NULL == ( fp = fopen( fname, "rb" ) ) ){
    printf("File %s open failed !\n", fname);
    return 1;
  }
  while( (i = readhex( fp, &addr, s )) >= 0 ){
    if( i ){
      if( addr + i > flashsize ){
	fclose( fp );
	my_exit( "Hex-file to large for target!", EXIT_ERROR );
      }
      far_copy( data, addr, s, i );
      addr += i;
      if( lastaddr < addr-1 )
	lastaddr = addr-1;
      addr++;
    }
  }
  fclose( fp );

  if( verify == 0 ){
    printf( "Program %s: 00000 - 00000", fname);
    sendcommand( PROGRAM );
  }else{
    sendcommand( VERIFY );
    if( empfang( TIMEOUT ) == BADCOMMAND ){
      printf("Verify not available\n");
      return 0;
    }
    printf( "Verify %s: 00000 - 00000", fname);
  }
  for( i = buffersize, addr = 0;; addr++ ){
    switch( d1 = far_byte( data, addr )){
      case ESCAPE:
      case 0x13: senden( ESCAPE );
		 d1 += ESC_SHIFT;
      default:   senden( d1 );
    }
    if( --i == 0 ){
      printf( "\b\b\b\b\b%05lX", addr + 1 );
      if( !verify && empfang( TIMEOUTP ) != CONTINUE ){
	printf( " failed!\n" );
	return 1;
      }
      i = buffersize;
    }
    if( addr == lastaddr ){
      senden( ESCAPE );
      senden( ESC_SHIFT );			// A5,80 = End
      printf( "\b\b\b\b\b%05lX", addr );
      if( empfang( TIMEOUTP ) == SUCCESS ){
	  printf( " successful" );
      }else{
	printf( " failed!\n" );
	return 1;
      }
      break;
    }
  }
  printf("\n");
  return 0;
}


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 long *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;
  unsigned int low_addr;

  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, &low_addr, 4 ))
    return -2;
  *addr &= 0xF0000L;
  *addr += low_addr;
  hp += 4;
  if( sscanhex( hp, &byte, 2 ))
    return -2;
  if( byte == 2 ){
    hp += 2;
    if( sscanhex( hp, &low_addr, 4 ))
      return -2;
    *addr = low_addr * 16L;
    return 0;					// segment record
  }
  if( byte == 1 )
    return 0;					// end record
  if( byte != 0 )
    return -2;					// error, unknown record
  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 2:
      case 3:
      case 4:
	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 1:
	if( i == SUCCESS )
	  return val;

      default:
	return -2;
    }
  }
}


int read_info( void )
{
  long i, j;
  char s[200];
  FILE *fp;

  sendcommand( REVISION );
  i = readval();
  printf("Bootloader V%lX.%lX\n", i>>8, i&0xFF );

  sendcommand( SIGNATURE );
  if( (i = readval()) == -1 )
    return 1;
  strncpy( s, _argv[0], 200 );			// get path+name
  strcpy( strchr( s, 0 ) - 3, "DEF" );          // name.EXE -> name.DEF
  if( (fp = fopen( s, "r" )) != NULL ){
    while( fgets( s, 200, fp )){
      if( sscanf( s, "%lX : %s", &j, s ) == 2 ){ // valid entry
	if( i == j )
	  break;
      }
      *s = 0;
    }
    fclose( fp );
  }
  printf("Target: %06lX %s\n", i, s );

  sendcommand( BUFFSIZE	);
  i = readval();
  if( i == -1 )
    return 1;
  buffersize = i;
  printf("Buffer: %ld Byte\n", i );

  sendcommand( USERFLASH );
  i = readval();
  if( i == -1 || i > MAXFLASH )
    return 1;
  flashsize = i;
  printf("Size available: %ld Byte\n", i );
  return 0;
}


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;
  }
}


int connect( void ){
  int COM[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
  char WAITSTRING[] = { '|', '/', '-', '\\' };
  int i = 1;
  int echo = 0;
  char *s;
  int j = 0;
  clock_t t = clock();

  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(;;){

    if( (clock() - t) > 6 ){
      t += 5;
      printf( "\b%c", WAITSTRING[++j&3] );
    }
    if( kbhit() ){
      getch();
      return 1;
    }
    s = Passwd;
    do{
      if( *s )
	senden( *s );
      else
	senden( 0xFF );
      i = empfang( 0 );
      if( i == Passwd[1] )
	echo = 1;				// echo received

      if( i == CONNECT ){
	s = "";
	if( echo ){
	  echocount = 1;
	  s = " (One wire)";
	}
	printf("\bConnected%s\n", s);
	sendcommand( COMMAND );
	for(;;){
	  switch( empfang( TIMEOUT )){ 		// clear RX buffer
	    case SUCCESS:
	    case -1:
	      return 0;
	  }
	}
      }
    }while( *s++ );
  }
}


int empfang( int te )
{
  unsigned char i;
  clock_t t = clock();				// actual time

  do{
    if( inportb(ComPort+5) & 1 ){		// byte received
      i = inportb(ComPort);
      if( echocount > 1 ){
	echocount--;                            // remove echo
	t = clock();				// restart timeout
	continue;
      }
      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 );
  }
}


int 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"
	  "/Pname\t\t Perform Program\n"
	  "/Vname\t\t Perform Verify\n"
	  "/Istring\t Init string\n"
	  "Press any Key ! " );
    getch();
    return 1;
  }
  return 0;
}


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
  outportb(ComPort+2, 0x07); 			// Enable FIFO
}


void senden(unsigned char c)
{
  if( echocount ){
    if( echocount > 1 )
      empfang( 0 );				// remove echo
    echocount++;
  }
  while( (inportb(ComPort+5) & 0x20) == 0);	/* Test Sendepuffer leer */
  outportb(ComPort, c );
  get_crc( c );					// calculate transmit CRC
}


void sendcommand(unsigned char c)
{
  if( echocount )
    echocount = 1;				// restart echo counter
  senden( COMMAND );
  senden( c );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -