Exemplo n.º 1
0
int main(void)
{
    uint8_t ch;

    /* 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__");
#if defined(__AVR_ATmega8__)
    SP = RAMEND;  // This is done by hardware reset
#endif

    /* Disable the watchdog timer to prevent
	 * eternal reset loop of doom and despair */
    ch = MCUSR;
    MCUSR = 0;
    if(ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
        if(eeprom_read_byte(EEPROM_IMG_STAT) == EEPROM_IMG_OK_VALUE)
            appStart();
	wdt_enable(WDTO_8S);

	// Wait to ensure startup of W5100
	_delay_ms(200);



	// Prescaler=0, ClkIO Period = 62,5ns
	// TCCR1B values:
	// 0x01 -> ClkIO/1 -> 62,5ns period, 4ms max
	// 0x02 -> ClkIO/8 -> 500ns period, 32ms max
	// 0X03 -> ClkIO/64 -> 4us period, 256ms max
	// 0x04 -> ClkIO/256 -> 16us period, 1024ms max
	// 0x05 -> ClkIO/1024 -> 64us period, 4096ms max
	// Set up Timer 1 as timekeeper for LED flashing
	TCCR1B = _BV(CS12); // Same thing as TCCR1B = 0x04;

	/* Write version information in the EEPROM */
	if(eeprom_read_byte(EEPROM_MAJVER) != ARIADNE_MAJVER)
		eeprom_write_byte(EEPROM_MAJVER, ARIADNE_MAJVER);
	if(eeprom_read_byte(EEPROM_MINVER) != ARIADNE_MINVER)
		eeprom_write_byte(EEPROM_MINVER, ARIADNE_MINVER);

	/* Initialize UART communication */
	serialInit();
	DBG_MAIN(tracePGMlnMain(mDebugMain_TITLE);)
Exemplo n.º 2
0
Common::Error Sword25Engine::run() {
	// Engine initialisation
	Common::Error error = appStart();
	if (error.getCode() != Common::kNoError) {
		appEnd();
		return error;
	}

	// Run the game
	bool runSuccess = appMain();

	// Engine de-initialisation
	bool deinitSuccess = appEnd();

	return (runSuccess && deinitSuccess) ? Common::kNoError : Common::kUnknownError;
}
Exemplo n.º 3
0
/* 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 pagelen_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__");
#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
  SP=RAMEND;  // This is done by hardware reset
#endif

  /*
   * modified Adaboot no-wait mod.
   * Pass the reset reason to app.  Also, it appears that an Uno poweron
   * can leave multiple reset flags set; we only want the bootloader to
   * run on an 'external reset only' status
   */
  ch = MCUSR;
  MCUSR = 0;
  if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
      appStart(ch);

#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
  UART_SRB = _BV(RXEN0) | _BV(TXEN0);
  UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
  UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#endif
#endif

  // Set up watchdog to trigger after 1s
  watchdogConfig(WATCHDOG_1S);

#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

  /* Forever loop: exits by causing WDT reset */
  for (;;) {
    /* get character from UART */
    ch = getch();

    if(ch == STK_GET_PARAMETER) {
      unsigned char which = getch();
      verifySpace();
      /*
       * Send optiboot version as "SW version"
       * Note that the references to memory are optimized away.
       */
      if (which == 0x82) {
	  putch(optiboot_version & 0xFF);
      } else if (which == 0x81) {
	  putch(optiboot_version >> 8);
      } else {
/* 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

    }
Exemplo n.º 5
0
void verifySpace() {
  if (getch() != CRC_EOP) appStart();
  putch(STK_INSYNC);
}
Exemplo n.º 6
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);
  }
}
Exemplo n.º 7
0
/* main program starts here */
int main(void) {
  uint8_t ch;
  uint8_t WaitTime = WATCHDOG_1S;  // Set watchdog to trigger after 1 second by default - value set to the watchdog later!


  /*
   * 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 pagelen_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:

  // Following lines enabled by Mark Griffiths to allow jumping directly to the boot loader from user code.
  cli();
  asm volatile ("clr __zero_reg__");
//#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
  SP=RAMEND;  // This is done by hardware reset
//#endif

  /*
   * modified Adaboot no-wait mod.
   * Pass the reset reason to app.  Also, it appears that an Uno poweron
   * can leave multiple reset flags set; we only want the bootloader to
   * run on an 'external reset only' status
   */
//  ch = MCUSR;
//  MCUSR = 0;
//  if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
//      appStart(ch);

  // Modified no wait mod by Mark Griffiths 8th of April 2015
  // This modification allows the majority of the reset flags to be kept 
  // unmodified in the MCUSR register for use by user sketches!

  // Previous method saved the MCUSR data in r2, but because it cleared 
  // MCUSR before attempting to update the flash memory, there was no way
  // for user code to distinguish between an external reset and a watchdog 
  // reset.  It also required extra code and an extra byte of RAM in the 
  // user sketch.

  ch = MCUSR;

  if (ch == 0) {
      WaitTime = WATCHDOG_8S;   // If no Reset Flags are set, it must mean that the user code jumped to the boot loader!  Wait 8 seconds for the firmware to be updated!
  } else {
      if ((ch & (_BV(WDRF) | _BV(EXTRF))) != _BV(EXTRF)) {    // To run the boot loader, External Reset Flag must be set and the Watchdog Flag MUST be cleared!  Otherwise jump straight to user code.
          MCUSR = ~(_BV(WDRF));
          appStart(ch);
      }
  }

#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
  UART_SRB = _BV(RXEN0) | _BV(TXEN0);
  UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
  UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#endif
#endif

  
  watchdogConfig(WaitTime);

#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

  /* Forever loop: exits by causing WDT reset */
  for (;;) {
    /* get character from UART */
    ch = getch();

    if(ch == STK_GET_PARAMETER) {
      unsigned char which = getch();
      verifySpace();
      /*
       * Send optiboot version as "SW version"
       * Note that the references to memory are optimized away.
       */
      if (which == 0x82) {
	  putch(optiboot_version & 0xFF);
      } else if (which == 0x81) {
	  putch(optiboot_version >> 8);
      } else {
Exemplo n.º 8
0
int main(int argc, char *argv[]) {
    eCmdLineStatus_t status;
    int keepGoing = 1;
    Uint32 lastTick;
    Uint32 current;
    Uint32 elapsed;
    Uint32 counter = 0;
    //GLuint img, fid;
    int iw, ih, fw, fh;
    const texture_t *dlg;
    const texture_t *misc;
    flubSlice_t *slice;
    //flubSlice_t *sliceTest;
    font_t *fnt;
    int eventCount;
    int pos;
    int w;
    gfxMeshObj_t *mesh;
    gfxMeshObj_t *fontMesh;
    sound_t *sound;
    char cwdbuf[1024];
    font_t *pfont;

    const texture_t *tex_misc;
    const texture_t *tex_dlg;
    const texture_t *tex_tiles;
    flubSlice_t *dlg_title;
    flubSlice_t *dlg_body;
    gfxMeshObj_t *meshFont;
    gfxMeshObj_t *meshChain;
    gfxMeshObj_t *meshDlg;
    gfxMeshObj_t *meshTiles;
    gfxMeshObj_t *meshMisc;
    gfxEffect_t *effect;

    int tileMap[127];
    char *scene[3] = {
            "#######\n#UIIIO#\n#JKKKL#\n#WWWWW#\n#######\n#######\n#######",
            "       \n       \n       \n  w P  \n    F  \nCCCCVCC\n       ",
            "       \n       \n       \n    D  \n       \n       \n       ",
    };

    tileMap['#'] = 0;
    tileMap['U'] = 23;
    tileMap['I'] = 7;
    tileMap['O'] = 24;
    tileMap['J'] = 21;
    tileMap['K'] = 5;
    tileMap['L'] = 22;
    tileMap['W'] = 16;
    tileMap['w'] = 32;
    tileMap['P'] = 36;
    tileMap['D'] = 37;
    tileMap['F'] = 33;
    tileMap['C'] = 34;
    tileMap['V'] = 19;

    flubSprite_t *sprites;

    //log_message = physfs_log;

    if(!appInit(argc, argv)) {
        return 1;
    }

    // Register command line params and config vars

#if 0
    infof("### Adding font ###################################");
    if(!flubFontLoad("flub/font/times.12.stbfont")) {
        errorf("Unable to load times font.");
    }
    if(!flubFontLoad("flub/font/courier.12.stbfont")) {
        errorf("Unable to load courier font.");
    }
#endif

    status = appStart(NULL);
    if(status != eCMDLINE_OK) {
        return ((status == eCMDLINE_EXIT_SUCCESS) ? 0 : 1);
    }

    //infof("Working dir: [%s]", getcwd(cwdbuf, sizeof(cwdbuf)));


    //enumDir("");
    //enumDir("assets");

    fnt = fontGet("consolas", 12, 0);
    if(fnt == NULL) {
        infof("Unable to get font");
        return 1;
    }
    fpsFont = fnt;
    //fid = fontGetGLImage(fnt, &fw, &fh);
    //fid = fontGetGLTexture(fnt);

    //info("Font loaded, targeting images.");

    //infof("Working dir: [%s]", getcwd(cwdbuf, sizeof(cwdbuf)));

    misc = texmgrGet("flub-keycap-misc");
    dlg = texmgrLoad( "work/dungeondlg2.gif", "dungeondlg2", GL_NEAREST, GL_NEAREST, 1, 255, 0, 255);
    //img = texmgrQuickLoad( "assets/misc/test_img.gif", GL_NEAREST, GL_NEAREST, 0, 0, 0, 0, &iw, &ih);
    footex = dlg;

    slice = gfxSliceCreate(dlg, 0, 0, 18, 22, 74, 69, 126, 106);
    //sliceTest = gfxSliceCreate(dlg, 145, 6, 150, 11, 182, 27, 186, 31);
    //infof("Texture id for flubmisc1 is %d", misc->id);

    //vboTestInit(misc->id);

    sound = audioSoundGet("resources/sounds/menumove.wav");

    mesh = gfxMeshCreate(MESH_QUAD_SIZE(40), 0, misc);
    //infof("The mesh is 0x%p", mesh);
    gfxTexMeshBlit(mesh, misc, 20, 20);
    //gfxMeshBlit(mesh, 220, 20);
    //gfxMeshBlit(mesh, 420, 20);
    //gfxMeshBlit(mesh, 20, 220);
    //gfxMeshBlit(mesh, 220, 220);
    //gfxMeshBlit(mesh, 420, 220);

    //infof("Vertices: %d", mesh->pos);

    fontMesh = gfxMeshCreate(256 * 2, GFX_MESH_FLAG_COLOR, NULL);
    gfxMeshTextureAssign(fontMesh, fontTextureGet(fnt));

    fontPos(150, 240);
    fontBlitCMesh(fontMesh, fnt, 'F');
    fontBlitCMesh(fontMesh, fnt, 'o');
    fontBlitCMesh(fontMesh, fnt, 'o');
    fontPos(150, 260);
    fontBlitStrMesh(fontMesh, fnt, "fontBlitStrMesh();");
    fontPos(150, 280);
    fontBlitStrNMesh(fontMesh, fnt, "fontBlitStrNMesh(); is too long", 19);
    fontPos(150, 300);
    fontBlitStrfMesh(fontMesh, fnt, "font%sStrf();", "Blit");
    fontPos(150, 320);
    fontBlitQCStrMesh(fontMesh, fnt, "font^2Blit^1QC^wStr();");
    fontPos(150, 340);
    fontBlitIntMesh(fontMesh, fnt, 12345);
    fontPos(150, 360);
    fontBlitFloatMesh(fontMesh, fnt, 12.345, 3);

    // Blitter test resources
    tex_misc = texmgrGet("flub-keycap-misc");
    tex_dlg = texmgrGet("dungeondlg2");
    tex_tiles = texmgrLoad( "work/tiletest.gif", "testtiles", GL_NEAREST, GL_NEAREST, 1, 255, 0, 255);

    sprites = gfxSpriteCreate(tex_tiles, 16, 16);

    dlg_title = gfxSliceCreate(tex_misc, 41, 17, 43, 19, 60, 26, 62, 28);
    dlg_body = gfxSliceCreate(tex_misc, 41, 29, 43, 30, 60, 40, 62, 42);

    // Create meshes for font, flubmisc, and flubsimplegui
    meshFont = gfxMeshCreate(MESH_QUAD_SIZE(100), GFX_MESH_FLAG_COLOR, fontTextureGet(fnt));
    meshDlg = gfxMeshCreate(MESH_QUAD_SIZE(200), GFX_MESH_FLAG_COLOR, tex_dlg);
    meshTiles = gfxMeshCreate(MESH_QUAD_SIZE(400), 0, tex_tiles);
    meshMisc = gfxMeshCreate(MESH_QUAD_SIZE(400), GFX_MESH_FLAG_COLOR, tex_misc);

    meshChain = meshFont;
    gfxMeshAppendToChain(meshChain, meshMisc);
    gfxMeshAppendToChain(meshChain, meshDlg);
    gfxMeshAppendToChain(meshChain, meshTiles);

    // Excercise mesh blitters
    gfxTexMeshBlit(meshChain, tex_misc, 400, 5);
    gfxTexMeshBlitSub(meshChain, tex_dlg, 145, 6, 186, 31, 400, 200, 450, 250);
    gfxTexMeshTile(meshChain, tex_dlg, 150, 11, 180, 25, 400, 260, 500, 400);
    blitMeshSpriteMap(meshChain, sprites, 200, 20, tileMap, scene, 3);
    gfxSpriteMeshBlitResize(meshChain, sprites, 36, 0, 0, 63, 63);


    gfxSliceMeshBlit(meshChain, dlg_title, 200, 300, 320, 315);
    gfxSliceMeshBlit(meshChain, dlg_body, 200, 316, 320, 440);
    gfxKeycapMeshBlit(meshChain, fnt, "META_WINDOWS", 200, 260, NULL, NULL);
    gfxKeycapMeshBlit(meshChain, fnt, "Ctrl", 240, 260, NULL, NULL);
    gfxKeycapMeshBlit(meshChain, fnt, "PgDn", 280, 260, NULL, NULL);

    effectMesh = meshDlg;
    effectStart = meshDlg->pos;
    gfxSliceMeshBlit(meshDlg, slice, 10, 50, 150, 190);
    effectStop = meshDlg->pos;

    effect = gfxEffectFade(effectMesh, effectStart, effectStop, 0.0, 1.0, 2000);
    effect->completed = fadeinCompleted;
    gfxEffectRegister(effect);


    if((!flubFontLoad("pirulen.30.stbfont")) ||
       ((pfont = fontGet("pirulen", 30, 0)) == NULL)) {
        fatal("Unable to load pirulen font");
        return 0;
    }

    inputActionBind("KEY_BACKQUOTE", "showconsole");
    //glBlendFunc(GL_ONE, GL_ZERO);
    //glDisable(GL_BLEND);
    //glEnable(GL_TEXTURE_2D);

    info("### Loading theme ###############");
    flubGuiThemeLoad("assets/data/flub-basic.theme");
    info("### Done loading theme ##########");

    lastTick = SDL_GetTicks();
    while (keepGoing) {
        current = SDL_GetTicks();
        elapsed = current - lastTick;
        lastTick = current;
        counter += elapsed;
        if(counter >= 2500) {
            if(sound != NULL) {
                //Mix_PlayChannel(0, sound, 0);
            }
            counter -= 2500;
        }
        // Process every event
        SDL_Event ev;
        // wait no more than 15ms to avoid exceeding 67 fps
        //while (SDL_WaitEventTimeout(&ev, 15)) {
        eventCount = 0;
        while(inputPollEvent(&ev)) {
            eventCount++;
            switch (ev.type) {
                case SDL_QUIT:
                    keepGoing = 0;
                    break;
                case SDL_TEXTINPUT:
                    break;
                case SDL_KEYUP:
                    switch (ev.key.keysym.sym) {
                        case SDLK_HOME:
                            break;
                        case SDLK_END:
                            break;
                        case SDLK_PAGEUP:
                            break;
                        case SDLK_PAGEDOWN:
                            break;
                        case SDLK_UP:
                        case SDLK_e:
                            break;
                        case SDLK_DOWN:
                        case SDLK_d:
                            break;
                        case SDLK_w:
                            break;
                        case SDLK_r:
                            break;
                        case SDLK_LEFT:
                        case SDLK_s:
                            break;
                        case SDLK_RIGHT:
                        case SDLK_f:
                            break;
                        case SDLK_ESCAPE:
                            keepGoing = 0;
                            break;
                        case SDLK_BACKQUOTE:
                            break;
    					case SDLK_RETURN:
    						break;
                    }
                    break;
                case SDL_KEYDOWN:
                    switch (ev.key.keysym.sym) {
                        case SDLK_HOME:
                            videoScreenshot("screenshot");
                            break;
                        case SDLK_END:
                            break;
                        case SDLK_PAGEUP:
                            break;
                        case SDLK_PAGEDOWN:
                            break;
                        case SDLK_UP:
                        case SDLK_e:
                            break;
                        case SDLK_DOWN:
                        case SDLK_d:
                            break;
                        case SDLK_w:
                            break;
                        case SDLK_r:
                            break;
                        case SDLK_LEFT:
                        case SDLK_s:
                            break;
                        case SDLK_RIGHT:
                        case SDLK_f:
                            break;
                        case SDLK_ESCAPE:
                            keepGoing = 0;
                            break;
                        case SDLK_BACKQUOTE:
                            /*
                            if(consoleVisible()) {
                                consoleShow(0);
                            } else {
                                consoleShow(1);
                            }
                            */
                            break;
                    }
                    break;
                case SDL_CONTROLLERBUTTONDOWN:
                    break;
                case SDL_CONTROLLERBUTTONUP:
                    break;
                case SDL_CONTROLLERAXISMOTION:
                    break;
            }
            if(eventCount >= BULK_EVENT_LIMIT) {
                break;
            }
        }
        videoClear();

        //glDisable(GL_DEPTH_TEST);
        //glDisable(GL_CULL_FACE);
        //glDisable(GL_BLEND);

        videoPushGLState();
        videoOrthoMode();

        glLoadIdentity();
        glColor3f(1.0, 1.0, 1.0);
        //glEnable(GL_BLEND);
        //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        //fontSetColor(1.0, 1.0, 1.0);
        //gfxBlitKeyStr(fnt, "Use [META_UP] and [META_DOWN] to select a menu option.", 10, 440, NULL, NULL);
        //gfxBlitKeyStr(fnt, "Use [~] to open the console.", 10, 460, NULL, NULL);


        glLoadIdentity();

        //gfxTexTile(tex_dlg, 150, 11, 180, 25, 200, 260, 298, 400);
        //gfxTexBlit(tex_misc, 200, 5);
        //gfxTexBlitSub(tex_misc, 0, 0, 127, 127, 0, 5, 127, 132);

        //gfxMeshRender(fontMesh);

        //gfxSliceBlit(dlg_title, 200, 300, 320, 315);
        //gfxSliceBlit(dlg_body, 200, 316, 320, 440);
        //gfxSliceBlit(slice, 10, 50, 150, 190);


        glLoadIdentity();

        //fontMode();
        //fontPos(10, 200);
        //fontBlitStr(pfont, "This Is A Test! Werd, yo!");
        //glLoadIdentity();
        //gfxTexBlit(fontTextureGet(pfont), 10, 200);

        //videoPushGLState();
        //videoOrthoMode();

        //vboTestRender();

        //gfxGLBlit(img, 380, 10, 380 + iw, 10 + ih);


        //fontSetColor(0.5, 1.0, 0.5);
        //fontSetColor(1.0, 1.0, 1.0);
        //gfxGLBlit(fid, 5, 5, fw, fh);

        //gfxTexBlit(misc, 25, 120);
        //gfxGLBlit(misc->id, 5, 100, 5 + misc->width, 100 + misc->height);


        gfxMeshRender(meshChain);

        //videoPopGLState();

        if(!appUpdate(current)) {
            keepGoing = 0;
        }
    }

    gfxMeshDestroy(mesh);

    return 0;
}
Exemplo n.º 9
0
int main(int argc, char *argv[]) {
    font_t *font;
    const texture_t *texture;
    const texture_t *misc;
    flubSlice_t *dlg_body;
    flubSlice_t *dlg_title;
    eCmdLineStatus_t status;
    int keepGoing = 1;
    Uint32 lastTick;
    Uint32 current;
    Uint32 elapsed;
    SDL_Event ev;
    int eventCount;
    FILE *fp;
    eThemerState_t state = eThemerStateType;
    tsMenuState_t menuState;
    tsMenuEntry_t menuEntries[] = {
            {"Bitmap", eCompBitmap},
            {"Animation", eCompAnimation},
            {"Tile", eCompTile},
            {"Slice", eCompSlice},
            {NULL, 0},
        };
    int pos = 0;
    int curx = 0;
    int cury = 0;
    compState_t parentComp, *comp, *walk;
    flubSimpleEdit_t *edit;
    const char *path = "flub-theme.txt";
    appCmdlineCtx_t appCtx = {.path = NULL};

    if(!appInit(argc, argv)) {
        return 1;
    }

    // Register command line params and config vars

    if((status = appStart(&appCtx)) != eCMDLINE_OK) {
        return ((status == eCMDLINE_EXIT_SUCCESS) ? 0 : 1);
    }
    if(appCtx.path != NULL) {
        path = appCtx.path;
    }

    if((fp = fopen(path, "a+t")) == NULL) {
        errorf("Failed to open theme output file.");
        return 1;
    } else {
        infof("Opened output file \"%s\"", path);
    }

    if((font = fontGet("consolas", 12, 0)) == NULL) {
        infof("Unable to get font");
        return 1;
    }

    texture = texmgrGet("flub-simple-gui");
    misc = texmgrGet("flub-keycap-misc");
    dlg_body = gfxSliceCreate(misc, 41, 29, 43, 30, 60, 40, 62, 42);
    dlg_title = gfxSliceCreate(misc, 41, 17, 43, 19, 60, 26, 62, 28);

    inputActionBind("KEY_BACKQUOTE", "showconsole");

    tsMenuInit(&menuState, font, menuEntries, 310, 45);
    edit = flubSimpleEditCreate(font, 30, 310, 70);
    tsCompStateInit(&parentComp, texture, menuState.pos);
    comp = &parentComp;

    lastTick = SDL_GetTicks();
    while (keepGoing) {
        current = SDL_GetTicks();
        elapsed = current - lastTick;
        lastTick = current;

        tsCompAnimUpdate(comp, elapsed);

        eventCount = 0;
        while(inputPollEvent(&ev)) {
            eventCount++;
            if(ev.type == SDL_QUIT) {
                keepGoing = 0;
                break;
            }

            if(ev.type == SDL_KEYDOWN) {
                if(ev.key.keysym.sym == SDLK_ESCAPE) {
                    state = eThemerStateConfirm;
                    break;
                } else if(ev.key.keysym.sym == SDLK_HOME) {
                    videoScreenshot("screenshot");
                    break;
                }
            }

            switch(state) {
                default:
                case eThemerStateType:
                    if(tsMenuInput(&menuState, &ev)) {
                        state = eThemerStatePoints;
                        comp = tsCompStateClear(comp);
                        curx = 0;
                        cury = 0;
                        tsCompStateInit(comp, texture, menuState.pos);
                    }
                    break;
                case eThemerStatePoints:
                    if(ev.type == SDL_KEYDOWN) {
                        switch (ev.key.keysym.sym) {
                            case SDLK_END:
                                flubSimpleEditSet(edit, "comp");
                                flubSimpleEditActive(edit, 1);
                                state = eThemerStateName;
                                break;
                            case SDLK_INSERT:
                                comp = tsCompStateAddFrame(comp);
                                break;
                            case SDLK_EQUALS:
                                comp = tsCompFrameNext(comp);
                                break;
                            case SDLK_BACKSLASH:
                                tsCompAnimToggle(comp);
                                break;
                            case SDLK_PAGEUP:
                                if(ev.key.keysym.mod & KMOD_SHIFT) {
                                    tsCompAnimAdjust(comp, 10);
                                } else {
                                    tsCompAnimAdjust(comp, 1);
                                }
                                break;
                            case SDLK_PAGEDOWN:
                                if(ev.key.keysym.mod & KMOD_SHIFT) {
                                    tsCompAnimAdjust(comp, -10);
                                } else {
                                    tsCompAnimAdjust(comp, -1);
                                }
                                if(comp->delay < 0) {
                                    comp->delay = 0;
                                }
                                break;
                            case SDLK_UP:
                                tsCompPosUpdate(comp, 0, -1,
                                                ((ev.key.keysym.mod & KMOD_SHIFT) ? 1 : 0),
                                                ((ev.key.keysym.mod & KMOD_CTRL) ? 1 : 0),
                                                &curx, &cury);
                                break;
                            case SDLK_DOWN:
                                tsCompPosUpdate(comp, 0, 1,
                                                ((ev.key.keysym.mod & KMOD_SHIFT) ? 1 : 0),
                                                ((ev.key.keysym.mod & KMOD_CTRL) ? 1 : 0),
                                                &curx, &cury);
                                break;
                            case SDLK_LEFT:
                                tsCompPosUpdate(comp, -1, 0,
                                                ((ev.key.keysym.mod & KMOD_SHIFT) ? 1 : 0),
                                                ((ev.key.keysym.mod & KMOD_CTRL) ? 1 : 0),
                                                &curx, &cury);
                                break;
                            case SDLK_RIGHT:
                                tsCompPosUpdate(comp, 1, 0,
                                                ((ev.key.keysym.mod & KMOD_SHIFT) ? 1 : 0),
                                                ((ev.key.keysym.mod & KMOD_CTRL) ? 1 : 0),
                                                &curx, &cury);
                                break;
                            case SDLK_RETURN:
                                tsCompNextPoint(comp, &curx, &cury);
                                break;
                        }
                    }
                    break;
                case eThemerStateName:
                    if(flubSimpleEditInput(edit, &ev)) {
                        // Save the entry
                        if(comp->type == eCompSlice) {
                            fprintf(fp,"%s %d %d %d %d %d %d %d %d\n", edit->buf,
                                    comp->pos[0][0], comp->pos[0][1],
                                    comp->pos[1][0], comp->pos[1][1],
                                    comp->pos[2][0], comp->pos[2][1],
                                    comp->pos[3][0], comp->pos[3][1]);
                        } else if(comp->type == eCompAnimation) {
                            fprintf(fp, "%s %d %d ", edit->buf,
                                    (comp->pos[1][0] - comp->pos[0][0] + 1),
                                    (comp->pos[1][1] - comp->pos[0][1]));
                            if(comp->parent == NULL) {
                                walk = comp;
                            } else {
                                walk = comp->parent;
                            }
                            for(; walk != NULL; walk = walk->next) {
                                fprintf(fp, "%d %d %d ", walk->pos[0][0], walk->pos[0][1], walk->delay);
                            }
                        } else {
                            fprintf(fp,"%s %d %d %d %d\n", edit->buf,
                                    comp->pos[0][0], comp->pos[0][1],
                                    comp->pos[1][0], comp->pos[1][1]);
                        }
                        state = eThemerStateType;
                        break;
                    }
                    break;
                case eThemerStateConfirm:
                    if(ev.type == SDL_KEYDOWN) {
                        switch (ev.key.keysym.sym) {
                            case SDLK_END:
                                keepGoing = 0;
                                break;
                            case SDLK_RETURN:
                                state = eThemerStateType;
                                break;
                        }
                        break;
                    }
                    break;
            }
            if(eventCount >= BULK_EVENT_LIMIT) {
                break;
            }
        }
        videoClear();

        videoPushGLState();
        videoOrthoMode();

        glLoadIdentity();
        glColor3f(1.0, 1.0, 1.0);

        // Title
        gfxSliceBlit(dlg_title, 0, 0, 639, 20);
        fontMode();
        fontPos(5, 5);
        fontSetColor(0.0, 0.0, 0.0);
        fontBlitStr(font, "Flub Themer");

        // Image
        glLoadIdentity();
        drawTexture(texture, 10, 30);

        // State name
        fontMode();
        fontSetColor(1.0, 1.0, 1.0);
        fontPos(300, 25);

        switch(state) {
            default:
            case eThemerStateType:
                fontBlitStr(font, "Select component type:");
                tsMenuDraw(&menuState);
                break;
            case eThemerStatePoints:
                fontBlitStr(font, "Select points:");
                drawFragment(texture, dlg_body, comp);
                drawCrosshair(misc, curx + 10, cury + 30);
                fontMode();
                fontPos(5, 300);
                fontSetColor(1.0, 1.0, 1.0);
                fontBlitStrf(font, "X: %3d  Y: %3d", curx, cury);
                tsCompPointInfo(comp, font, 310, 50);
                if((comp->type == eCompAnimation) &&
                   (((comp->parent != NULL) && (comp->parent->animGo)) ||
                    (comp->animGo))) {
                    fontPos(310, 250);
                    fontSetColor(1.0, 1.0, 1.0);
                    fontBlitStrf(font, "Animating");
                }
                break;
            case eThemerStateName:
                fontBlitStr(font, "Select component type:");
                fontMode();
                fontPos(310, 50);
                fontSetColor(1.0, 1.0, 1.0);
                fontBlitStr(font, "Enter component name");
                flubSimpleEditDraw(edit);
                break;
            case eThemerStateConfirm:
                fontBlitStr(font, "Are you sure you want to quit?");
                gfxBlitKeyStr(font, "Press [End] to exit, [Return] to continue.", 310, 50, NULL, NULL);
                break;
        }

        if(!appUpdate(current)) {
            keepGoing = 0;
        }
    }
    fclose(fp);
    return 0;
}
Exemplo n.º 10
0
Arquivo: optiboot.c Projeto: 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;
	}
      }