Dean Camera committed May 08, 2010 1 2 /* LUFA Library  Dean Camera committed Feb 04, 2012 3  Copyright (C) Dean Camera, 2012.  4   Dean Camera committed May 08, 2010 5  dean [at] fourwalledcubicle [dot] com  Dean Camera committed Oct 28, 2010 6  www.lufa-lib.org  Dean Camera committed May 08, 2010 7 8 9 */ /*  Dean Camera committed Feb 04, 2012 10  Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)  Dean Camera committed May 08, 2010 11   12  Permission to use, copy, modify, distribute, and sell this  Dean Camera committed May 08, 2010 13  software and its documentation for any purpose is hereby granted  14  without fee, provided that the above copyright notice appear in  Dean Camera committed May 08, 2010 15  all copies and that both that the copyright notice and this  16 17 18  permission notice and warranty disclaimer appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the  Dean Camera committed May 08, 2010 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40  software without specific, written prior permission. The author disclaim all warranties with regard to this software, including all implied warranties of merchantability and fitness. In no event shall the author be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software. */ /** \file * * Main source file for the DFU class bootloader. This file contains the complete bootloader logic. */ #define INCLUDE_FROM_BOOTLOADER_C #include "BootloaderDFU.h" /** Flag to indicate if the bootloader is currently running in secure mode, disallowing memory operations * other than erase. This is initially set to the value set by SECURE_MODE, and cleared by the bootloader  Dean Camera committed Feb 09, 2011 41  * once a memory erase has completed in a bootloader session.  Dean Camera committed May 08, 2010 42  */  Dean Camera committed Feb 10, 2011 43 static bool IsSecure = SECURE_MODE;  Dean Camera committed May 08, 2010 44 45 46 47 48  /** Flag to indicate if the bootloader should be running, or should exit and allow the application code to run * via a soft reset. When cleared, the bootloader will abort, the USB interface will shut down and the application * jumped to via an indirect jump to location 0x0000 (or other location specified by the host). */  Dean Camera committed Feb 10, 2011 49 static bool RunBootloader = true;  Dean Camera committed May 08, 2010 50 51 52 53 54 55  /** Flag to indicate if the bootloader is waiting to exit. When the host requests the bootloader to exit and * jump to the application address it specifies, it sends two sequential commands which must be properly * acknowledged. Upon reception of the first the RunBootloader flag is cleared and the WaitForExit flag is set, * causing the bootloader to wait for the final exit command before shutting down. */  Dean Camera committed Feb 10, 2011 56 static bool WaitForExit = false;  Dean Camera committed May 08, 2010 57 58  /** Current DFU state machine state, one of the values in the DFU_State_t enum. */  Dean Camera committed Feb 10, 2011 59 static uint8_t DFU_State = dfuIDLE;  Dean Camera committed May 08, 2010 60 61 62 63  /** Status code of the last executed DFU command. This is set to one of the values in the DFU_Status_t enum after * each operation, and returned to the host when a Get Status DFU request is issued. */  Dean Camera committed Feb 10, 2011 64 static uint8_t DFU_Status = OK;  Dean Camera committed May 08, 2010 65 66  /** Data containing the DFU command sent from the host. */  Dean Camera committed Feb 10, 2011 67 static DFU_Command_t SentCommand;  Dean Camera committed May 08, 2010 68 69 70 71 72  /** Response to the last issued Read Data DFU command. Unlike other DFU commands, the read command * requires a single byte response from the bootloader containing the read data when the next DFU_UPLOAD command * is issued by the host. */  Dean Camera committed Feb 10, 2011 73 static uint8_t ResponseByte;  Dean Camera committed May 08, 2010 74 75 76 77  /** Pointer to the start of the user application. By default this is 0x0000 (the reset vector), however the host * may specify an alternate address when issuing the application soft-start command. */  Dean Camera committed Feb 10, 2011 78 static AppPtr_t AppStartPtr = (AppPtr_t)0x0000;  Dean Camera committed May 08, 2010 79 80 81 82  /** 64-bit flash page number. This is concatenated with the current 16-bit address on USB AVRs containing more than * 64KB of flash memory. */  Dean Camera committed Feb 10, 2011 83 static uint8_t Flash64KBPage = 0;  Dean Camera committed May 08, 2010 84 85 86 87  /** Memory start address, indicating the current address in the memory being addressed (either FLASH or EEPROM * depending on the issued command from the host). */  Dean Camera committed Feb 10, 2011 88 static uint16_t StartAddr = 0x0000;  Dean Camera committed May 08, 2010 89   Dean Camera committed Jun 05, 2011 90 /** Memory end address, indicating the end address to read from/write to in the memory being addressed (either FLASH  Dean Camera committed May 08, 2010 91 92  * of EEPROM depending on the issued command from the host). */  Dean Camera committed Feb 10, 2011 93 static uint16_t EndAddr = 0x0000;  Dean Camera committed May 08, 2010 94   Dean Camera committed May 10, 2012 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 /** Magic lock for forced application start. If the HWBE fuse is programmed and BOOTRST is unprogrammed, the bootloader * will start if the /HWB line of the AVR is held low and the system is reset. However, if the /HWB line is still held * low when the application attempts to start via a watchdog reset, the bootloader will re-start. If set to the value * \ref MAGIC_BOOT_KEY the special init function \ref Application_Jump_Check() will force the application to start. */ uint32_t MagicBootKey ATTR_NO_INIT; /** Special startup routine to check if the bootloader was started via a watchdog reset, and if the magic application * start key has been loaded into \ref MagicBootKey. If the bootloader started via the watchdog and the key is valid, * this will force the user application to start via a software jump. */ void Application_Jump_Check(void) { // If the reset source was the bootloader and the key is correct, clear it and jump to the application if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY)) { MagicBootKey = 0; AppStartPtr(); } }  Dean Camera committed May 08, 2010 116   117 /** Main program entry point. This routine configures the hardware required by the bootloader, then continuously  Dean Camera committed May 08, 2010 118 119 120 121 122 123 124  * runs the bootloader processing routine until instructed to soft-exit, or hard-reset via the watchdog to start * the loaded application code. */ int main(void) { /* Configure hardware required by the bootloader */ SetupHardware();  125   126 127 128 129 130 131 132  #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) /* Disable JTAG debugging */ MCUCR |= (1 << JTD); MCUCR |= (1 << JTD); /* Enable pull-up on the JTAG TCK pin so we can use it to select the mode */ PORTF |= (1 << 4);  Dean Camera committed Apr 08, 2011 133  Delay_MS(10);  134 135 136  /* If the TCK pin is not jumpered to ground, start the user application instead */ RunBootloader = (!(PINF & (1 << 4)));  Dean Camera committed Dec 23, 2011 137   138 139  /* Re-enable JTAG debugging */ MCUCR &= ~(1 << JTD);  Dean Camera committed Dec 23, 2011 140  MCUCR &= ~(1 << JTD);  141 142  #endif  143 144 145  /* Turn on first LED on the board to indicate that the bootloader has started */ LEDs_SetAllLEDs(LEDS_LED1);  Dean Camera committed May 08, 2010 146 147 148 149 150 151  /* Enable global interrupts so that the USB stack can function */ sei(); /* Run the USB management task while the bootloader is supposed to be running */ while (RunBootloader || WaitForExit) USB_USBTask();  152   Dean Camera committed May 08, 2010 153 154  /* Reset configured hardware back to their original states for the user application */ ResetHardware();  155   Dean Camera committed May 08, 2010 156 157 158 159 160  /* Start the user application */ AppStartPtr(); } /** Configures all hardware required for the bootloader. */  Dean Camera committed Jan 15, 2012 161 static void SetupHardware(void)  Dean Camera committed May 08, 2010 162 163 164 165 166 167 168 { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); wdt_disable(); /* Disable clock division */ clock_prescale_set(clock_div_1);  169   Dean Camera committed May 08, 2010 170 171 172 173  /* Relocate the interrupt vector table to the bootloader section */ MCUCR = (1 << IVCE); MCUCR = (1 << IVSEL);  Dean Camera committed Jan 29, 2012 174  /* Initialize the USB and other board hardware drivers */  Dean Camera committed May 08, 2010 175  USB_Init();  176  LEDs_Init();  Dean Camera committed Dec 23, 2011 177   178 179 180  /* Bootloader active LED toggle timer initialization */ TIMSK1 = (1 << TOIE1); TCCR1B = ((1 << CS11) | (1 << CS10));  Dean Camera committed May 08, 2010 181 182 183 } /** Resets all configured hardware required for the bootloader back to their original states. */  Dean Camera committed Jan 15, 2012 184 static void ResetHardware(void)  Dean Camera committed May 08, 2010 185 {  Dean Camera committed Jan 29, 2012 186  /* Shut down the USB and other board hardware drivers */  187  USB_Disable();  Dean Camera committed Jan 29, 2012 188  LEDs_Disable();  189   Dean Camera committed May 08, 2010 190 191 192 193 194  /* Relocate the interrupt vector table back to the application section */ MCUCR = (1 << IVCE); MCUCR = 0; }  195 196 197 198 199 200 /** ISR to periodically toggle the LEDs on the board to indicate that the bootloader is active. */ ISR(TIMER1_OVF_vect, ISR_BLOCK) { LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2); }  Dean Camera committed Nov 05, 2010 201 202 203 /** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to * the device from the USB host before passing along unhandled control requests to the library for processing * internally.  Dean Camera committed May 08, 2010 204  */  Dean Camera committed Nov 05, 2010 205 void EVENT_USB_Device_ControlRequest(void)  Dean Camera committed Dec 23, 2011 206 {  207 208 209 210 211 212  /* Ignore any requests that aren't directed to the DFU interface */ if ((USB_ControlRequest.bmRequestType & (CONTROL_REQTYPE_TYPE | CONTROL_REQTYPE_RECIPIENT)) != (REQTYPE_CLASS | REQREC_INTERFACE)) { return; }  Dean Camera committed May 08, 2010 213   Dean Camera committed Apr 23, 2011 214 215 216 217 218 219  /* Activity - toggle indicator LEDs */ LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2); /* Get the size of the command and data from the wLength value */ SentCommand.DataSize = USB_ControlRequest.wLength;  Dean Camera committed May 08, 2010 220 221  switch (USB_ControlRequest.bRequest) {  Dean Camera committed Feb 10, 2011 222  case DFU_REQ_DNLOAD:  Dean Camera committed May 08, 2010 223  Endpoint_ClearSETUP();  224   Dean Camera committed May 08, 2010 225 226 227 228 229  /* Check if bootloader is waiting to terminate */ if (WaitForExit) { /* Bootloader is terminating - process last received command */ ProcessBootloaderCommand();  230   Dean Camera committed May 08, 2010 231 232 233  /* Indicate that the last command has now been processed - free to exit bootloader */ WaitForExit = false; }  234   Dean Camera committed May 08, 2010 235 236 237 238  /* If the request has a data stage, load it into the command struct */ if (SentCommand.DataSize) { while (!(Endpoint_IsOUTReceived()))  239  {  Dean Camera committed May 08, 2010 240 241 242 243 244  if (USB_DeviceState == DEVICE_STATE_Unattached) return; } /* First byte of the data stage is the DNLOAD request's command */  Dean Camera committed Apr 04, 2011 245  SentCommand.Command = Endpoint_Read_8();  246   Dean Camera committed May 08, 2010 247 248  /* One byte of the data stage is the command, so subtract it from the total data bytes */ SentCommand.DataSize--;  249   Dean Camera committed May 08, 2010 250 251 252 253  /* Load in the rest of the data stage as command parameters */ for (uint8_t DataByte = 0; (DataByte < sizeof(SentCommand.Data)) && Endpoint_BytesInEndpoint(); DataByte++) {  Dean Camera committed Apr 04, 2011 254  SentCommand.Data[DataByte] = Endpoint_Read_8();  Dean Camera committed May 08, 2010 255 256  SentCommand.DataSize--; }  257   Dean Camera committed May 08, 2010 258 259 260  /* Process the command */ ProcessBootloaderCommand(); }  261   Dean Camera committed May 08, 2010 262 263  /* Check if currently downloading firmware */ if (DFU_State == dfuDNLOAD_IDLE)  264  {  Dean Camera committed May 08, 2010 265 266 267 268 269 270 271 272 273 274 275  if (!(SentCommand.DataSize)) { DFU_State = dfuIDLE; } else { /* Throw away the filler bytes before the start of the firmware */ DiscardFillerBytes(DFU_FILLER_BYTES_SIZE); /* Throw away the packet alignment filler bytes before the start of the firmware */ DiscardFillerBytes(StartAddr % FIXED_CONTROL_ENDPOINT_SIZE);  276   Dean Camera committed May 08, 2010 277 278  /* Calculate the number of bytes remaining to be written */ uint16_t BytesRemaining = ((EndAddr - StartAddr) + 1);  279   Dean Camera committed May 08, 2010 280 281 282 283  if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00)) // Write flash { /* Calculate the number of words to be written from the number of bytes to be written */ uint16_t WordsRemaining = (BytesRemaining >> 1);  284   Dean Camera committed May 08, 2010 285 286 287 288 289  union { uint16_t Words[2]; uint32_t Long; } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}};  290   Dean Camera committed May 08, 2010 291 292 293 294 295 296 297 298 299 300 301  uint32_t CurrFlashPageStartAddress = CurrFlashAddress.Long; uint8_t WordsInFlashPage = 0; while (WordsRemaining--) { /* Check if endpoint is empty - if so clear it and wait until ready for next packet */ if (!(Endpoint_BytesInEndpoint())) { Endpoint_ClearOUT(); while (!(Endpoint_IsOUTReceived()))  302  {  Dean Camera committed May 08, 2010 303 304 305 306 307 308  if (USB_DeviceState == DEVICE_STATE_Unattached) return; } } /* Write the next word into the current flash page */  Dean Camera committed Apr 04, 2011 309  boot_page_fill(CurrFlashAddress.Long, Endpoint_Read_16_LE());  Dean Camera committed May 08, 2010 310 311 312 313 314 315 316 317 318 319 320  /* Adjust counters */ WordsInFlashPage += 1; CurrFlashAddress.Long += 2; /* See if an entire page has been written to the flash page buffer */ if ((WordsInFlashPage == (SPM_PAGESIZE >> 1)) || !(WordsRemaining)) { /* Commit the flash page to memory */ boot_page_write(CurrFlashPageStartAddress); boot_spm_busy_wait();  321   Dean Camera committed May 08, 2010 322 323 324 325 326 327 328 329 330 331 332 333  /* Check if programming incomplete */ if (WordsRemaining) { CurrFlashPageStartAddress = CurrFlashAddress.Long; WordsInFlashPage = 0; /* Erase next page's temp buffer */ boot_page_erase(CurrFlashAddress.Long); boot_spm_busy_wait(); } } }  334   Dean Camera committed May 08, 2010 335 336  /* Once programming complete, start address equals the end address */ StartAddr = EndAddr;  337   Dean Camera committed May 08, 2010 338 339 340 341 342 343 344 345 346 347 348 349 350  /* Re-enable the RWW section of flash */ boot_rww_enable(); } else // Write EEPROM { while (BytesRemaining--) { /* Check if endpoint is empty - if so clear it and wait until ready for next packet */ if (!(Endpoint_BytesInEndpoint())) { Endpoint_ClearOUT(); while (!(Endpoint_IsOUTReceived()))  351  {  Dean Camera committed May 08, 2010 352 353 354 355 356 357  if (USB_DeviceState == DEVICE_STATE_Unattached) return; } } /* Read the byte from the USB interface and write to to the EEPROM */  Dean Camera committed Apr 04, 2011 358  eeprom_write_byte((uint8_t*)StartAddr, Endpoint_Read_8());  359   Dean Camera committed May 08, 2010 360 361 362 363  /* Adjust counters */ StartAddr++; } }  364   Dean Camera committed May 08, 2010 365 366 367 368 369 370 371 372 373 374  /* Throw away the currently unused DFU file suffix */ DiscardFillerBytes(DFU_FILE_SUFFIX_SIZE); } } Endpoint_ClearOUT(); Endpoint_ClearStatusStage(); break;  Dean Camera committed Feb 10, 2011 375  case DFU_REQ_UPLOAD:  Dean Camera committed May 08, 2010 376 377 378  Endpoint_ClearSETUP(); while (!(Endpoint_IsINReady()))  379  {  Dean Camera committed May 08, 2010 380 381 382  if (USB_DeviceState == DEVICE_STATE_Unattached) return; }  383   Dean Camera committed May 08, 2010 384 385 386 387 388 389  if (DFU_State != dfuUPLOAD_IDLE) { if ((DFU_State == dfuERROR) && IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01)) // Blank Check { /* Blank checking is performed in the DFU_DNLOAD request - if we get here we've told the host that the memory isn't blank, and the host is requesting the first non-blank address */  Dean Camera committed Apr 04, 2011 390  Endpoint_Write_16_LE(StartAddr);  Dean Camera committed May 08, 2010 391 392 393 394  } else { /* Idle state upload - send response to last issued command */  Dean Camera committed Apr 04, 2011 395  Endpoint_Write_8(ResponseByte);  Dean Camera committed May 08, 2010 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421  } } else { /* Determine the number of bytes remaining in the current block */ uint16_t BytesRemaining = ((EndAddr - StartAddr) + 1); if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00)) // Read FLASH { /* Calculate the number of words to be written from the number of bytes to be written */ uint16_t WordsRemaining = (BytesRemaining >> 1); union { uint16_t Words[2]; uint32_t Long; } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}}; while (WordsRemaining--) { /* Check if endpoint is full - if so clear it and wait until ready for next packet */ if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE) { Endpoint_ClearIN(); while (!(Endpoint_IsINReady()))  422  {  Dean Camera committed May 08, 2010 423 424 425 426 427 428 429  if (USB_DeviceState == DEVICE_STATE_Unattached) return; } } /* Read the flash word and send it via USB to the host */ #if (FLASHEND > 0xFFFF)  Dean Camera committed Apr 04, 2011 430  Endpoint_Write_16_LE(pgm_read_word_far(CurrFlashAddress.Long));  Dean Camera committed May 08, 2010 431  #else  Dean Camera committed Apr 04, 2011 432  Endpoint_Write_16_LE(pgm_read_word(CurrFlashAddress.Long));  Dean Camera committed May 08, 2010 433 434 435 436 437  #endif /* Adjust counters */ CurrFlashAddress.Long += 2; }  438   Dean Camera committed May 08, 2010 439 440 441 442 443 444 445 446 447 448 449  /* Once reading is complete, start address equals the end address */ StartAddr = EndAddr; } else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x02)) // Read EEPROM { while (BytesRemaining--) { /* Check if endpoint is full - if so clear it and wait until ready for next packet */ if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE) { Endpoint_ClearIN();  450   Dean Camera committed May 08, 2010 451  while (!(Endpoint_IsINReady()))  452  {  Dean Camera committed May 08, 2010 453 454 455 456 457 458  if (USB_DeviceState == DEVICE_STATE_Unattached) return; } } /* Read the EEPROM byte and send it via USB to the host */  Dean Camera committed Apr 04, 2011 459  Endpoint_Write_8(eeprom_read_byte((uint8_t*)StartAddr));  Dean Camera committed May 08, 2010 460 461 462 463 464 465 466 467 468 469 470 471 472 473  /* Adjust counters */ StartAddr++; } } /* Return to idle state */ DFU_State = dfuIDLE; } Endpoint_ClearIN(); Endpoint_ClearStatusStage(); break;  Dean Camera committed Feb 10, 2011 474  case DFU_REQ_GETSTATUS:  Dean Camera committed May 08, 2010 475  Endpoint_ClearSETUP();  476   Dean Camera committed May 08, 2010 477  /* Write 8-bit status value */  Dean Camera committed Apr 04, 2011 478  Endpoint_Write_8(DFU_Status);  479   Dean Camera committed May 08, 2010 480  /* Write 24-bit poll timeout value */  Dean Camera committed Apr 04, 2011 481 482  Endpoint_Write_8(0); Endpoint_Write_16_LE(0);  483   Dean Camera committed May 08, 2010 484  /* Write 8-bit state value */  Dean Camera committed Apr 04, 2011 485  Endpoint_Write_8(DFU_State);  Dean Camera committed May 08, 2010 486 487  /* Write 8-bit state string ID number */  Dean Camera committed Apr 04, 2011 488  Endpoint_Write_8(0);  Dean Camera committed May 08, 2010 489 490  Endpoint_ClearIN();  491   Dean Camera committed May 08, 2010 492  Endpoint_ClearStatusStage();  493  break;  Dean Camera committed Feb 10, 2011 494  case DFU_REQ_CLRSTATUS:  Dean Camera committed May 08, 2010 495  Endpoint_ClearSETUP();  496   Dean Camera committed May 08, 2010 497 498 499 500 501  /* Reset the status value variable to the default OK status */ DFU_Status = OK; Endpoint_ClearStatusStage(); break;  Dean Camera committed Feb 10, 2011 502  case DFU_REQ_GETSTATE:  Dean Camera committed May 08, 2010 503  Endpoint_ClearSETUP();  504   Dean Camera committed May 08, 2010 505  /* Write the current device state to the endpoint */  Dean Camera committed Apr 04, 2011 506  Endpoint_Write_8(DFU_State);  507   Dean Camera committed May 08, 2010 508  Endpoint_ClearIN();  509   Dean Camera committed May 08, 2010 510 511  Endpoint_ClearStatusStage(); break;  Dean Camera committed Feb 10, 2011 512  case DFU_REQ_ABORT:  Dean Camera committed May 08, 2010 513  Endpoint_ClearSETUP();  514   Dean Camera committed May 08, 2010 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537  /* Reset the current state variable to the default idle state */ DFU_State = dfuIDLE; Endpoint_ClearStatusStage(); break; } } /** Routine to discard the specified number of bytes from the control endpoint stream. This is used to * discard unused bytes in the stream from the host, including the memory program block suffix. * * \param[in] NumberOfBytes Number of bytes to discard from the host from the control endpoint */ static void DiscardFillerBytes(uint8_t NumberOfBytes) { while (NumberOfBytes--) { if (!(Endpoint_BytesInEndpoint())) { Endpoint_ClearOUT(); /* Wait until next data packet received */ while (!(Endpoint_IsOUTReceived()))  538  {  Dean Camera committed May 08, 2010 539 540 541 542 543 544  if (USB_DeviceState == DEVICE_STATE_Unattached) return; } } else {  Dean Camera committed Apr 04, 2011 545  Endpoint_Discard_8();  Dean Camera committed May 08, 2010 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566  } } } /** Routine to process an issued command from the host, via a DFU_DNLOAD request wrapper. This routine ensures * that the command is allowed based on the current secure mode flag value, and passes the command off to the * appropriate handler function. */ static void ProcessBootloaderCommand(void) { /* Check if device is in secure mode */ if (IsSecure) { /* Don't process command unless it is a READ or chip erase command */ if (!(((SentCommand.Command == COMMAND_WRITE) && IS_TWOBYTE_COMMAND(SentCommand.Data, 0x00, 0xFF)) || (SentCommand.Command == COMMAND_READ))) { /* Set the state and status variables to indicate the error */ DFU_State = dfuERROR; DFU_Status = errWRITE;  567   Dean Camera committed May 08, 2010 568 569  /* Stall command */ Endpoint_StallTransaction();  570   Dean Camera committed May 08, 2010 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609  /* Don't process the command */ return; } } /* Dispatch the required command processing routine based on the command type */ switch (SentCommand.Command) { case COMMAND_PROG_START: ProcessMemProgCommand(); break; case COMMAND_DISP_DATA: ProcessMemReadCommand(); break; case COMMAND_WRITE: ProcessWriteCommand(); break; case COMMAND_READ: ProcessReadCommand(); break; case COMMAND_CHANGE_BASE_ADDR: if (IS_TWOBYTE_COMMAND(SentCommand.Data, 0x03, 0x00)) // Set 64KB flash page command Flash64KBPage = SentCommand.Data[2]; break; } } /** Routine to concatenate the given pair of 16-bit memory start and end addresses from the host, and store them * in the StartAddr and EndAddr global variables. */ static void LoadStartEndAddresses(void) { union { uint8_t Bytes[2]; uint16_t Word; } Address[2] = {{.Bytes = {SentCommand.Data[2], SentCommand.Data[1]}}, {.Bytes = {SentCommand.Data[4], SentCommand.Data[3]}}};  610   Dean Camera committed May 08, 2010 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625  /* Load in the start and ending read addresses from the sent data packet */ StartAddr = Address[0].Word; EndAddr = Address[1].Word; } /** Handler for a Memory Program command issued by the host. This routine handles the preparations needed * to write subsequent data from the host into the specified memory. */ static void ProcessMemProgCommand(void) { if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00) || // Write FLASH command IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01)) // Write EEPROM command { /* Load in the start and ending read addresses */ LoadStartEndAddresses();  626   Dean Camera committed May 08, 2010 627 628 629 630 631 632 633 634  /* If FLASH is being written to, we need to pre-erase the first page to write to */ if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00)) { union { uint16_t Words[2]; uint32_t Long; } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}};  635   Dean Camera committed May 08, 2010 636 637 638 639  /* Erase the current page's temp buffer */ boot_page_erase(CurrFlashAddress.Long); boot_spm_busy_wait(); }  640   Dean Camera committed May 08, 2010 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676  /* Set the state so that the next DNLOAD requests reads in the firmware */ DFU_State = dfuDNLOAD_IDLE; } } /** Handler for a Memory Read command issued by the host. This routine handles the preparations needed * to read subsequent data from the specified memory out to the host, as well as implementing the memory * blank check command. */ static void ProcessMemReadCommand(void) { if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00) || // Read FLASH command IS_ONEBYTE_COMMAND(SentCommand.Data, 0x02)) // Read EEPROM command { /* Load in the start and ending read addresses */ LoadStartEndAddresses(); /* Set the state so that the next UPLOAD requests read out the firmware */ DFU_State = dfuUPLOAD_IDLE; } else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01)) // Blank check FLASH command { uint32_t CurrFlashAddress = 0; while (CurrFlashAddress < BOOT_START_ADDR) { /* Check if the current byte is not blank */ #if (FLASHEND > 0xFFFF) if (pgm_read_byte_far(CurrFlashAddress) != 0xFF) #else if (pgm_read_byte(CurrFlashAddress) != 0xFF) #endif { /* Save the location of the first non-blank byte for response back to the host */ Flash64KBPage = (CurrFlashAddress >> 16); StartAddr = CurrFlashAddress;  677   Dean Camera committed May 08, 2010 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699  /* Set state and status variables to the appropriate error values */ DFU_State = dfuERROR; DFU_Status = errCHECK_ERASED; break; } CurrFlashAddress++; } } } /** Handler for a Data Write command issued by the host. This routine handles non-programming commands such as * bootloader exit (both via software jumps and hardware watchdog resets) and flash memory erasure. */ static void ProcessWriteCommand(void) { if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x03)) // Start application { /* Indicate that the bootloader is terminating */ WaitForExit = true;  Dean Camera committed Aug 05, 2010 700 701  /* Check if data supplied for the Start Program command - no data executes the program */ if (SentCommand.DataSize)  Dean Camera committed May 08, 2010 702  {  Dean Camera committed Aug 05, 2010 703  if (SentCommand.Data[1] == 0x01) // Start via jump  Dean Camera committed May 08, 2010 704 705 706 707 708 709 710  { union { uint8_t Bytes[2]; AppPtr_t FuncPtr; } Address = {.Bytes = {SentCommand.Data[4], SentCommand.Data[3]}};  Dean Camera committed Aug 05, 2010 711  /* Load in the jump address into the application start address pointer */  Dean Camera committed May 08, 2010 712  AppStartPtr = Address.FuncPtr;  Dean Camera committed Aug 05, 2010 713 714 715 716 717 718  } } else { if (SentCommand.Data[1] == 0x00) // Start via watchdog {  Dean Camera committed May 10, 2012 719 720 721  /* Unlock the forced application start mode of the bootloader if it is restarted */ MagicBootKey = MAGIC_BOOT_KEY;  Dean Camera committed Aug 05, 2010 722 723 724 725 726  /* Start the watchdog to reset the AVR once the communications are finalized */ wdt_enable(WDTO_250MS); } else // Start via jump {  Dean Camera committed May 08, 2010 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748  /* Set the flag to terminate the bootloader at next opportunity */ RunBootloader = false; } } } else if (IS_TWOBYTE_COMMAND(SentCommand.Data, 0x00, 0xFF)) // Erase flash { uint32_t CurrFlashAddress = 0; /* Clear the application section of flash */ while (CurrFlashAddress < BOOT_START_ADDR) { boot_page_erase(CurrFlashAddress); boot_spm_busy_wait(); boot_page_write(CurrFlashAddress); boot_spm_busy_wait(); CurrFlashAddress += SPM_PAGESIZE; } /* Re-enable the RWW section of flash as writing to the flash locks it out */ boot_rww_enable();  749   Dean Camera committed May 08, 2010 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769  /* Memory has been erased, reset the security bit so that programming/reading is allowed */ IsSecure = false; } } /** Handler for a Data Read command issued by the host. This routine handles bootloader information retrieval * commands such as device signature and bootloader version retrieval. */ static void ProcessReadCommand(void) { const uint8_t BootloaderInfo[3] = {BOOTLOADER_VERSION, BOOTLOADER_ID_BYTE1, BOOTLOADER_ID_BYTE2}; const uint8_t SignatureInfo[3] = {AVR_SIGNATURE_1, AVR_SIGNATURE_2, AVR_SIGNATURE_3}; uint8_t DataIndexToRead = SentCommand.Data[1]; if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00)) // Read bootloader info ResponseByte = BootloaderInfo[DataIndexToRead]; else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01)) // Read signature byte ResponseByte = SignatureInfo[DataIndexToRead - 0x30]; }  Dean Camera committed Dec 23, 2011 770