/* main program starts here */
int main(void) {
  uint8_t ch;

  /*
   * Making these local and in registers prevents the need for initializing
   * them, and also saves space because code no longer stores to memory.
   * (initializing address keeps the compiler happy, but isn't really
   *  necessary, and uses 4 bytes of flash.)
   */
  register uint16_t address = 0;
  register uint8_t  length;

  // After the zero init loop, this is the first code to run.
  //
  // This code makes the following assumptions:
  //  No interrupts will execute
  //  SP points to RAMEND
  //  r1 contains zero
  //
  // If not, uncomment the following instructions:
  // cli();
  asm volatile ("clr __zero_reg__");
#ifdef __AVR_ATmega8__
  SP=RAMEND;  // This is done by hardware reset
#endif

  // Adaboot no-wait mod
  ch = MCUSR;
  MCUSR = 0;
  if (!(ch & _BV(EXTRF))) appStart();

#if LED_START_FLASHES > 0
  // Set up Timer 1 for timeout counter
  TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
#endif
#ifndef SOFT_UART
#ifdef __AVR_ATmega8__
  UCSRA = _BV(U2X); //Double speed mode USART
  UCSRB = _BV(RXEN) | _BV(TXEN);  // enable Rx & Tx
  UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0);  // config USART; 8N1
  UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#else
  UCSR0A = _BV(U2X0); //Double speed mode USART0
  UCSR0B = _BV(RXEN0) | _BV(TXEN0);
  UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
  UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#endif
#endif

  // Set up watchdog to trigger after 500ms
  watchdogConfig(WATCHDOG_1S);

  /* Set LED pin as output */
  LED_DDR |= _BV(LED);

#ifdef SOFT_UART
  /* Set TX pin as output */
  UART_DDR |= _BV(UART_TX_BIT);
#endif

#if LED_START_FLASHES > 0
  /* Flash onboard LED to signal entering of bootloader */
  flash_led(LED_START_FLASHES * 2);
#endif

  /* Forever loop */
  for (;;) {
    /* get character from UART */
    ch = getch();

    if(ch == STK_GET_PARAMETER) {
      unsigned char which = getch();
      verifySpace();
      if (which == 0x82) {
        /*
         * Send optiboot version as "minor SW version"
         */
        putch(OPTIBOOT_MINVER);
      } else if (which == 0x81) {
          putch(OPTIBOOT_MAJVER);
      } else {
        /*
         * GET PARAMETER returns a generic 0x03 reply for
         * other parameters - enough to keep Avrdude happy
         */
        putch(0x03);
      }
    }
    else if(ch == STK_SET_DEVICE) {
      // SET DEVICE is ignored
      getNch(20);
    }
    else if(ch == STK_SET_DEVICE_EXT) {
      // SET DEVICE EXT is ignored
      getNch(5);
    }
    else if(ch == STK_LOAD_ADDRESS) {
      // LOAD ADDRESS
      uint16_t newAddress;
      newAddress = getch();
      newAddress = (newAddress & 0xff) | (getch() << 8);
#ifdef RAMPZ
      // Transfer top bit to RAMPZ
      RAMPZ = (newAddress & 0x8000) ? 1 : 0;
#endif
      newAddress += newAddress; // Convert from word address to byte address
      address = newAddress;
      verifySpace();
    }
    else if(ch == STK_UNIVERSAL) {
      // UNIVERSAL command is ignored
      getNch(4);
      putch(0x00);
    }
    /* Write memory, length is big endian and is in bytes */
    else if(ch == STK_PROG_PAGE) {
      // PROGRAM PAGE - we support flash programming only, not EEPROM
      uint8_t *bufPtr;
      uint16_t addrPtr;

      getch();                  /* getlen() */
      length = getch();
      getch();

      // If we are in RWW section, immediately start page erase
      if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);

      // While that is going on, read in page contents
      bufPtr = buff;
      do *bufPtr++ = getch();
      while (--length);

      // If we are in NRWW section, page erase has to be delayed until now.
      // Todo: Take RAMPZ into account
      if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);

      // Read command terminator, start reply
      verifySpace();

      // If only a partial page is to be programmed, the erase might not be complete.
      // So check that here
      boot_spm_busy_wait();

#ifdef VIRTUAL_BOOT_PARTITION
      if ((uint16_t)(void*)address == 0) {
        // This is the reset vector page. We need to live-patch the code so the
        // bootloader runs.
        //
        // Move RESET vector to WDT vector
        uint16_t vect = buff[0] | (buff[1]<<8);
        rstVect = vect;
        wdtVect = buff[8] | (buff[9]<<8);
        vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
        buff[8] = vect & 0xff;
        buff[9] = vect >> 8;

        // Add jump to bootloader at RESET vector
        buff[0] = 0x7f;
        buff[1] = 0xce; // rjmp 0x1d00 instruction
      }
#endif

      // Copy buffer into programming buffer
      bufPtr = buff;
      addrPtr = (uint16_t)(void*)address;
      ch = SPM_PAGESIZE / 2;
      do {
        uint16_t a;
        a = *bufPtr++;
        a |= (*bufPtr++) << 8;
        __boot_page_fill_short((uint16_t)(void*)addrPtr,a);
        addrPtr += 2;
      } while (--ch);

      // Write from programming buffer
      __boot_page_write_short((uint16_t)(void*)address);
      boot_spm_busy_wait();

#if defined(RWWSRE)
      // Reenable read access to flash
      boot_rww_enable();
#endif

    }
Example #2
0
/* main program starts here */
int main(void) {
  // After the zero init loop, this is the first code to run.
  //
  // This code makes the following assumptions:
  //  No interrupts will execute
  //  SP points to RAMEND
  //  r1 contains zero
  //
  // If not, uncomment the following instructions:
  cli();
  SP=RAMEND;  // This is done by hardware reset
  asm volatile ("clr __zero_reg__");

  uint8_t ch;


  // Adaboot no-wait mod
  ch = MCUSR;
  MCUSR = 0;
  if (!(ch & _BV(EXTRF))) appStart();

  // Set up watchdog to trigger after 500ms
  watchdogConfig(WATCHDOG_OFF);

  	DDRD = 0;
	PORTD = 0;
	PORTC = 0;
	DDRC = C3_WR | C2_RD;


  /* Forever loop */
  for (;;) {
    /* get character from UART */
    ch = getch();

    if(ch == STK_GET_PARAMETER) {
      // GET PARAMETER returns a generic 0x03 reply - enough to keep Avrdude happy
      getNch(1);
      putch(0x03);
    }
    else if(ch == STK_SET_DEVICE) {
      // SET DEVICE is ignored
      getNch(20);
    }
    else if(ch == STK_SET_DEVICE_EXT) {
      // SET DEVICE EXT is ignored
      getNch(5);
    }
    else if(ch == STK_LOAD_ADDRESS) {
      // LOAD ADDRESS
      address = getch();
      address = (address & 0xff) | (getch() << 8);
      address += address; // Convert from word address to byte address
      verifySpace();
    }
    else if(ch == STK_UNIVERSAL) {
      // UNIVERSAL command is ignored
      getNch(4);
      putch(0x00);
    }
    /* Write memory, length is big endian and is in bytes  */
    else if(ch == STK_PROG_PAGE) {
      // PROGRAM PAGE - we support flash programming only, not EEPROM
      uint8_t *bufPtr;
      uint16_t addrPtr;

      getLen();

      // Immediately start page erase - this will 4.5ms
      boot_page_erase((uint16_t)(void*)address);

      // While that is going on, read in page contents
      bufPtr = buff;
      do *bufPtr++ = getch();
      while (--length);

      // Read command terminator, start reply
      verifySpace();
      
      // If only a partial page is to be programmed, the erase might not be complete.
      // So check that here
      boot_spm_busy_wait();


      // Copy buffer into programming buffer
      bufPtr = buff;
      addrPtr = (uint16_t)(void*)address;
      ch = SPM_PAGESIZE / 2;
      do {
        uint16_t a;
        a = *bufPtr++;
        a |= (*bufPtr++) << 8;
        boot_page_fill((uint16_t)(void*)addrPtr,a);
        addrPtr += 2;
      } while (--ch);
      
      // Write from programming buffer
      boot_page_write((uint16_t)(void*)address);
      boot_spm_busy_wait();

      // Reenable read access to flash
      boot_rww_enable();


    }
    /* Read memory block mode, length is big endian.  */
    else if(ch == STK_READ_PAGE) {
      // READ PAGE - we only read flash
      getLen();
      verifySpace();

      do putch(pgm_read_byte_near(address++));
      while (--length);
    }

    /* Get device signature bytes  */
    else if(ch == STK_READ_SIGN) {
      // READ SIGN - return what Avrdude wants to hear
      verifySpace();
      putch(SIGNATURE_0);
      putch(SIGNATURE_1);
      putch(SIGNATURE_2);
    }
    else if (ch == 'Q') {
      // Adaboot no-wait mod
      watchdogConfig(WATCHDOG_16MS);
      verifySpace();
    }
    else {
      // This covers the response to commands like STK_ENTER_PROGMODE
      verifySpace();
    }
    putch(STK_OK);
  }
}
Example #3
0
uint8_t proccessCommand()
{
	uint8_t ch;

	ch = getch();

	if(ch == STK_GET_PARAMETER) {
		unsigned char which = getch();
		verifySpace();
		if(which == 0x82) {
			/*
			 * Send tftpboot version as "minor SW version"
			 */
			putch(ARIADNE_MINVER);
		} else if(which == 0x81) {
			putch(ARIADNE_MAJVER);
		} else {
			/*
			 * GET PARAMETER returns a generic 0x03 reply for
			 * other parameters - enough to keep Avrdude happy
			 */
			putch(0x03);
		}
	} else if(ch == STK_SET_DEVICE) {
		// SET DEVICE is ignored
		getNch(20);
	} else if(ch == STK_SET_DEVICE_EXT) {
		// SET DEVICE EXT is ignored
		getNch(4);
	} else if(ch == STK_LOAD_ADDRESS) {
		// LOAD ADDRESS
		uint16_t newAddress;
		newAddress = getch();
		newAddress = (newAddress & 0xff) | (getch() << 8);

#ifdef RAMPZ
		// Transfer top bit to RAMPZ
		RAMPZ = (newAddress & 0x8000) ? 1 : 0;
#endif

		newAddress += newAddress; // Convert from word address to byte address
		address = newAddress;
		verifySpace();
	} else if(ch == STK_UNIVERSAL) {
		// UNIVERSAL command is ignored
		getNch(4);
		putch(0x00);
	}
	/* Write memory, length is big endian and is in bytes */
	else if(ch == STK_PROG_PAGE) {
		// This should probably go somewhere but I don't yet know it's place
		//eeprom_write_byte(EEPROM_IMG_STAT, EEPROM_IMG_BAD_VALUE);
		// PROGRAM PAGE - we support flash programming only, not EEPROM
		uint8_t  buff[256];
		uint8_t* bufPtr;
		uint16_t addrPtr;

		getch();			/* getlen() */
		length = getch();
		getch();

		// If we are in RWW section, immediately start page erase
		if(address < NRWWSTART) boot_page_erase((uint16_t)(void*)address);

		// While that is going on, read in page contents
		bufPtr = buff;
		do* bufPtr++ = getch();
		while(--length);

		// If we are in NRWW section, page erase has to be delayed until now.
		// Todo: Take RAMPZ into account
		if(address >= NRWWSTART) boot_page_erase((uint16_t)(void*)address);

		// Read command terminator, start reply
		verifySpace();

		// If only a partial page is to be programmed, the erase might not be complete.
		// So check that here
		boot_spm_busy_wait();

		// Copy buffer into programming buffer
		bufPtr = buff;
		addrPtr = (uint16_t)(void*)address;
		ch = SPM_PAGESIZE / 2;
		do {
			uint16_t a;
			a = *bufPtr++;
			a |= (*bufPtr++) << 8;
			boot_page_fill((uint16_t)(void*)addrPtr, a);
			addrPtr += 2;
		} while(--ch);

		// Write from programming buffer
		boot_page_write((uint16_t)(void*)address);
		boot_spm_busy_wait();

#if defined(RWWSRE)
		// Reenable read access to flash
		boot_rww_enable();
#endif
	}
	/* Read memory block mode, length is big endian.  */
	else if(ch == STK_READ_PAGE) {
		// READ PAGE - we only read flash
		getch();			/* getlen() */
		length = getch();
		getch();

		verifySpace();

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560)
		//      do putch(pgm_read_byte_near(address++));
		//      while (--length);
		do {
			uint8_t result;
			__asm__("elpm %0,Z\n":"=r"(result):"z"(address));
			putch(result);
			address++;
		} while(--length);
#else
		do putch(pgm_read_byte_near(address++));
		while(--length);
#endif
	}
Example #4
0
File: optiboot.c Project: seco/OU
/* main program starts here */
int main(void) {
  uint8_t ch;
  uint16_t pmask;

  /*
   * Making these local and in registers prevents the need for initializing
   * them, and also saves space because code no longer stores to memory.
   * (initializing address keeps the compiler happy, but isn't really
   *  necessary, and uses 4 bytes of flash.)
   */
  register uint16_t address = 0;
  register uint16_t length;

  // After the zero init loop, this is the first code to run.
  //
  // This code makes the following assumptions:
  //  No interrupts will execute
  //  SP points to RAMEND
  //  r1 contains zero
  //
  // If not, uncomment the following instructions:
  // cli();
  asm volatile ("clr __zero_reg__");
  SP=RAMEND;  // This is done by hardware reset

  // Adaboot no-wait mod
  ch = MCUSR;
  MCUSR = 0;
  if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
	appStart(ch);

  // WDT clock by 32KHz IRC
  PMCR = 0x80;
  PMCR = 0x93;

#if EXT_OSC == 1
#warning Using external crystal now!!!
  // for case of 16MHz crystall, no clock divider
  PMCR = 0x80;
  PMCR = 0x97;
  for(ch = 0xf; ch > 0; --ch);
  PMCR = 0x80;
  PMCR = 0xb7;

  CLKPR = 0x80;
  CLKPR = 0x00;

  // external crsyall flag
  VDTCR = 0x80;
  VDTCR = 0x4C;
#else
  // system clock: 16MHz system clock
  CLKPR = 0x80;
  CLKPR = 0x01;
#endif

#if LED_START_FLASHES > 0
  // Set up Timer 1 for timeout counter
  TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
#endif

#ifndef SOFT_UART
#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
  UCSRA = _BV(U2X); //Double speed mode USART
  UCSRB = _BV(RXEN) | _BV(TXEN);  // enable Rx & Tx
  UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0);  // config USART; 8N1
  UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#else
  //UART_SRA = _BV(U2X0); //Double speed mode USART0
  ch = PMXCR | 0x03;
  PMXCR = 0x80;
  PMXCR = ch;

  UART_SRB = _BV(RXEN0) | _BV(TXEN0);
  UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
  UART_SRL = (uint8_t)( F_CPU / (BAUD_RATE * 16L) - 1 );
  //UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#endif
#endif

  // Set up watchdog to trigger after 500ms
  watchdogConfig(WATCHDOG_16MS);

#if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH)
  /* Set LED pin as output */
  LED_DDR |= _BV(LED);
#endif

#ifdef SOFT_UART
  /* Set TX pin as output */
  UART_DDR |= _BV(UART_TX_BIT);
#endif

#if LED_START_FLASHES > 0
  /* Flash onboard LED to signal entering of bootloader */
  flash_led(LED_START_FLASHES * 2);
#endif

  // page erased flag
  pmask = 0;

  /* Forever loop */
  for (;;) {
    /* get character from UART */
    ch = getch();

    if(ch == STK_GET_PARAMETER) {
      unsigned char which = getch();
      verifySpace();
      if (which == 0x82) {
	/*
	 * Send optiboot version as "minor SW version"
	 */
	putch(OPTIBOOT_MINVER);
      } else if (which == 0x81) {
	  putch(OPTIBOOT_MAJVER);
      } else {
	/*
	 * GET PARAMETER returns a generic 0x03 reply for
         * other parameters - enough to keep Avrdude happy
	 */
	putch(0x03);
      }
    }
    else if(ch == STK_SET_DEVICE) {
      // SET DEVICE is ignored
      getNch(20);
    }
    else if(ch == STK_SET_DEVICE_EXT) {
      // SET DEVICE EXT is ignored
      getNch(5);
    }
    else if(ch == STK_LOAD_ADDRESS) {
      // LOAD ADDRESS
      uint16_t newAddress;
      newAddress = getch();
      newAddress = (newAddress & 0xff) | (getch() << 8);
#ifdef RAMPZ
      // Transfer top bit to RAMPZ
      RAMPZ = (newAddress & 0x8000) ? 1 : 0;
#endif
      newAddress += newAddress; // Convert from word address to byte address
      address = newAddress;
      verifySpace();
    }
    else if(ch == STK_UNIVERSAL) {
      // UNIVERSAL command is ignored
      getNch(4);
      putch(0x00);
    }
    /* Write memory, length is big endian and is in bytes */
    else if(ch == STK_PROG_PAGE) {
      // PROGRAM PAGE - we support flash programming only, not EEPROM
      uint8_t *bufPtr;
      uint8_t bval;
      uint16_t len;
      length = (uint16_t)getch() << 8; /* getlen() */
      length += getch();
      bval = getch();

      // If we are in RWW section, immediately start page erase
      //if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);

      // While that is going on, read in page contents
      bufPtr = buff;
      len = length;
      do *bufPtr++ = getch();
      while (--len);

      EEARL = 0; 
      EEARH = address >> 8;
      ch = EEARH >> 2;	// 1KB page size

      if((0 == (pmask & (((uint16_t)1 << ch)))) && bval == 'F') { 
	pmask |= ((uint16_t)1 << ch);
      	// do page erase here
      	EECR = 0x94;
      	EECR = 0x92;
      	asm("nop"); asm("nop");      
      }

      // Read command terminator, start reply
      verifySpace();

      // If only a partial page is to be programmed, the erase might not be complete.
      // So check that here
      //boot_spm_busy_wait();
      if (bval == 'E') {
	  for(len = 0; len < length; len++) {
	    if(address >= 512)
		    break;
	    EEARL = address++;
	    EEARH = address >> 8;
	    EEDR = buff[len];
	    EECR = 0x04;
	    EECR = 0x02;
	  }
      } else {
#ifdef VIRTUAL_BOOT_PARTITION
	if ((uint16_t)(void*)address == 0) {
	  // This is the reset vector page. We need to live-patch the code so the
	  // bootloader runs.
	  //
	  // Move RESET vector to WDT vector
	  uint16_t vect = buff[0] | (buff[1] << 8);
	  rstVect = vect;
	  wdtVect = buff[8] | (buff[9] << 8);
	  vect -= 4;
	  buff[8] = vect & 0xff;
	  buff[9] = vect >> 8;

	  // Add jump to bootloader at RESET vector
	  buff[0] = 0xff;
	  buff[1] = 0xcd; // jmp 
	}
#endif
      	// Write from programming buffer
	bufPtr = buff;
      	for(length = 0; length < SPM_PAGESIZE; length+=2) {
	      EEARL = 0; EEDR = *bufPtr++;
	      EEARL = 1; EEDR = *bufPtr++;
	      EEARL = (address + length) & 0xff;
	      EECR = 0xA4;
	      EECR = 0xA2;
	}
      }
Example #5
0
/* main program starts here */
void optiboot(void) {
	uint8_t ch;

	/* Forever loop */
	for (;;) {
		/* get character from UART */
		ch = getch();
		uint8_t reply = STK_OK;

		if(ch == STK_GET_PARAMETER) {
			// GET PARAMETER returns a generic 0x03 reply - enough to keep Avrdude happy
			getNch(1);
			putch(0x03);
		}
		else if(ch == STK_SET_DEVICE) {
			// SET DEVICE is ignored
			getNch(20);
		}
		else if(ch == STK_SET_DEVICE_EXT) {
			// SET DEVICE EXT is ignored
			getNch(5);
		}
		else if(ch == STK_LOAD_ADDRESS) {
			// LOAD ADDRESS
			uint16_t address = getch();
			address = (address & 0xff) | (getch() << 8);
			verifySpace();

			// address is in words right now
			if (address % (SPM_PAGESIZE / 2)) {
				reply = STK_FAILED;
			}
			else {
				// Convert to page address
				page = address / (SPM_PAGESIZE / 2);
			}
		}
		else if(ch == STK_UNIVERSAL) {
			// UNIVERSAL command is ignored
			getNch(4);
			putch(0x00);
		}
		/* Write memory, length is big endian and is in bytes  */
		else if(ch == STK_PROG_PAGE) {
			// PROGRAM PAGE
			uint8_t *bufPtr = buff;

			// we support flash programming only, not EEPROM
			if ((getLen() == 'E') ||
				(length > SPM_PAGESIZE) ||
				(page >= (CONFIG_BOOTLDR_START_ADDR / SPM_PAGESIZE)))
			{
				reply = STK_FAILED;
			}

			// Clear the buffer
			memset(buff, 0xff, sizeof(buff));

			// Read in page contents
			do *bufPtr++ = getch();
			while (--length);

			// Read command terminator, start reply
			verifySpace();

			if (reply == STK_OK) {
				// Write the page
				stubboot_write_page(page, buff);
			}
		}
		/* Read memory block mode, length is big endian.  */
		else if(ch == STK_READ_PAGE) {
			// READ PAGE - we only read flash
			if (getLen() == 'E') {
				reply = STK_FAILED;
			}
			verifySpace();

#if (FLASHEND > USHRT_MAX)
			uint_farptr_t address = (uint_farptr_t)page * SPM_PAGESIZE;
#else
			uint16_t address = page * SPM_PAGESIZE;
#endif

			while (length--) {
#if (FLASHEND > USHRT_MAX)
				putch(pgm_read_byte_far(address++));
#else
				putch(pgm_read_byte_near(address++));
#endif
			}
		}
		/* Get device signature bytes  */
		else if(ch == STK_READ_SIGN) {
			// READ SIGN - return what Avrdude wants to hear
			verifySpace();
			putch(SIGNATURE_0);
			putch(SIGNATURE_1);
			putch(SIGNATURE_2);
		}
		else {
			// This covers the response to commands like STK_ENTER_PROGMODE
			verifySpace();
		}

		putch(reply);
	}
}
/* main program starts here */
void bootloader(void)
{
#ifdef ADABOOT
  char firstcharzero=0;
#endif
  uint8_t ch,ch2;
  uint16_t w;

  error_count = 0;
  initSerial();


  /* forever loop */
  for (;;) 
    {
    bitTgl(UsbLed);

      if (error_count >= MAX_ERROR_COUNT)  // Probably normal serial traffic is causing this.
        {
          releaseChipAccess();
          return;
          //initSerial();
          //error_count = 0;
        }

      /* get character from UART */
      //bitSet(BluLed);
      ch = bootldrgetch();
      if (ch ==0)
        {
        releaseChipAccess();
        return;
        }
      //bitClr(BluLed);
      //blinkLed(GrnLedId,100*mSec,1);
      /* A bunch of if...else if... gives smaller code than switch...case ! */

#if  0 //def ADABOOT
      // Hello is anyone home ?   lady ada hack -  BBR
      if(ch=='0') {
        firstcharzero = 1; // we got an appropriate bootloader instruction
        nothing_response();
      } 
	
      else if (firstcharzero == 0) {
        // the first character we got is not '0', lets bail!
        // autoreset via watchdog (sneaky!)
        // return();
      }	
#else

      /* Hello is anyone home ? */ 
      if(ch=='0') 
        {
          nothing_response();
	}
#endif

      /* Request programmer ID */
      /* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry  */
      /* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares.  */
      else if(ch=='1') {
        if (bootldrgetch() == ' ') {
          putNch(pgmrId,9);
        } else {
          ++error_count;
        }
      }


      /* AVR ISP/STK500 board commands  DON'T CARE so default nothing_response */
      else if(ch=='@') {
        ch2 = bootldrgetch();
        if (ch2>0x85) bootldrgetch();
        nothing_response();
      }


      /* AVR ISP/STK500 board requests */
      /* Cmnd_STK_GET_PARAMETER 0x41 */
      else if(ch=='A') {
        ch2 = bootldrgetch();
        if(ch2==0x80) byte_response(HW_VER);		// Hardware version
        else if(ch2==0x81) byte_response(SW_MAJOR);	// Software major version
        else if(ch2==0x82) byte_response(SW_MINOR);	// Software minor version
        else if(ch2==0x98) byte_response(0x03);		// Unknown but seems to be required by avr studio 3.56
        else byte_response(0x00);				// Covers various unnecessary responses we don't care about
      }


      /* Cmnd_STK_SET_DEVICE 0x42
      Device Parameters  DON'T CARE, DEVICE IS FIXED  */
      else if(ch=='B') {
        getNch(20);
        nothing_response();
      }


      /* Cmnd_SET_DEVICE_EXT 0x45 */
      else if(ch=='E') {
        getNch(5);
        nothing_response();
      }

      /* P: Enter programming mode  */
      else if(ch=='P')
        {
        if (!initChipAccess(&devId[1]))
          {
          failed_response();
          }
        else nothing_response();
        }
        
      /* R: Erase device, don't care as we will erase one page at a time anyway.  */
      else if(ch=='R')
        {
        eraseDevice();
        nothing_response();
        }


      /* Leave programming mode  */
      else if(ch=='Q') 
        {
        nothing_response();
        delay(5*mSec);
        releaseChipAccess();        
        allDone();
        return;
#ifdef WATCHDOG_MODS
        assert(0);
#endif
        }


      /* Set address, little endian. EEPROM in bytes, FLASH in words  */
      /* Perhaps extra address bytes may be added in future to support > 128kB FLASH.  */
      /* This might explain why little endian was used here, big endian used everywhere else.  */
      else if(ch=='U') {
        address.word = myget2LE();
        //address.byte[0] = bootldrgetch();
        //address.byte[1] = bootldrgetch();
        nothing_response();
      }


      /* Universal SPI programming command. Used for fuses and lock bits.  */
      else if(ch=='V') {
        unsigned char spicmdbuf[4];
        bootldrgetNch(spicmdbuf,4);
                
        if (0) { // spicmdbuf[0] == 0x30) {
          if (spicmdbuf[2] == 0) {
            byte_response(SIG1);
          } else if (spicmdbuf[2] == 1) {
            byte_response(SIG2); 
          } else {
            byte_response(SIG3);
          } 
        } 
        // Call my erase device embedded routine if the erase device SPI cmd comes in
        else if ((spicmdbuf[0] == 0xac) && (spicmdbuf[1] == 0x80))
        {
        eraseDevice();
        byte_response(0);
        }
        // Don't let them program the fuse bits into a non-working clock
        // This SPI on this chip can't go slow enough to work with very slow AVR clocks (<=1mhz)
        else if ((spicmdbuf[0] == 0xAC) && (spicmdbuf[1] == 0xA0) && (((spicmdbuf[3]&0x80) == 0) || ((spicmdbuf[3]&0x0f) == 3)))
        {
              failed_response();
        }       
        else
        {
          byte_response(issueSpiCmd(spicmdbuf));
        }
      }


      /* Write memory, length is big endian and is in bytes  */
      else if(ch=='d') {
        length.word = myget2BE();
        //length.byte[1] = bootldrgetch();
        //length.byte[0] = bootldrgetch();
        flags.eeprom = 0;
        if (bootldrgetch() == 'E') flags.eeprom = 1;
        for (w=0;w<length.word;w++) 
          {
            buff[w] = bootldrgetch();	                        // Store data in buffer, can't keep up with serial data stream whilst programming pages
          }
        if (bootldrgetch() == ' ') 
          {
            if (flags.eeprom) {		                //Write to EEPROM one byte at a time
              address.word <<= 1;
              for(w=0;w<length.word;w++) {
                eeprom_write_byte((void *)address.word,buff[w]);
                address.word++;
              }			
            }
            else {					        //Write to FLASH one page at a time
              if (address.byte[1]>127) address_high = 0x01;	//Only possible with m128, m256 will need 3rd address byte. FIXME
              else address_high = 0x00;

              address.word = address.word << 1;	        //address * 2 -> byte location
              /* if ((length.byte[0] & 0x01) == 0x01) length.word++;	//Even up an odd number of bytes */
              //if ((length.byte[0] & 0x01)) length.word++;	//Even up an odd number of bytes
              if (length.word&1) length.word++; // Even up an odd number of bytes
              flash_write((void*)address.word, length.word, address_high, buff);
            }
            putNch(endStmt,2);
            //myputch(0x14);
            //myputch(0x10);
          } else {
          ++error_count;
        }		
      }


      /* Read memory block mode, length is big endian.  */
      else if(ch=='t') 
        {
        length.word = myget2BE();
        //length.byte[1] = bootldrgetch();
        //length.byte[0] = bootldrgetch();
#if defined(__AVR_ATmega128__)  || defined(__AVR_ATmega1280__)
        if (address.word>0x7FFF) flags.rampz = 1;		// No go with m256, FIXME
        else flags.rampz = 0;
#endif
        address.word = address.word << 1;	        // address * 2 -> byte location
        if (bootldrgetch() == 'E') flags.eeprom = 1;
        else flags.eeprom = 0;
        if (bootldrgetch() == ' ') 
          {		                // Command terminator
          myputch(0x14);
          if (1)
            {		        // Can handle odd and even lengths okay
            if (flags.eeprom) 
              { // Byte access EEPROM read
              for (w=0;w < length.word;w++,address.word++)
                {
                myputch(eeprom_read_byte((void *)address.word));
                }
              }
            else 
              {
              int bpos = 0;
              
              for (w=0;w < length.word;w++,address.word++,bpos++)
                {
                if (!flags.rampz) buff[bpos] = pgm_read_byte_near((void*)address.word);
#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)
                else buff[bpos] = pgm_read_byte_far(address.word + 0x10000);
                // Hmmmm, yuck  FIXME when m256 arrvies
#endif
                if (bpos == 63)
                  {
                  putNch(buff,64);
                  bpos = -1;
                  }
                }
              if (bpos > 0)
                {
                  putNch(buff,bpos);
                }
              }
            }
          myputch(0x10);
          }
        }


      /* Get device signature bytes  */
      else if(ch=='u') {
        if (bootldrgetch() == ' ') {
          bitSet(UsbLed);
          putNch(devId,5);
        } else {
          ++error_count;
        }
      }


      /* Read oscillator calibration byte */
      else if(ch=='v') {
        byte_response(0x00);
      }


#ifdef MONITOR
      /* here come the extended monitor commands by Erik Lins */
      /* check for three times exclamation mark pressed */
      else if(ch=='!') monitor();
#endif
      else   /* Garbled 1st character */
        {
          //printf("garbled character %d %c\n",ch,ch);
          ++error_count;
        }

    } /* end of forever loop */

}