Upgrade doxygen configuration files to the latest version.
[pub/lufa.git] / Bootloaders / DFU / BootloaderDFU.c
index 0385bfc..aeb4d9f 100644 (file)
@@ -1,13 +1,13 @@
 /*
              LUFA Library
 /*
              LUFA Library
-     Copyright (C) Dean Camera, 2014.
+     Copyright (C) Dean Camera, 2021.
 
   dean [at] fourwalledcubicle [dot] com
            www.lufa-lib.org
 */
 
 /*
 
   dean [at] fourwalledcubicle [dot] com
            www.lufa-lib.org
 */
 
 /*
-  Copyright 2014  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+  Copyright 2021  Dean Camera (dean [at] fourwalledcubicle [dot] com)
 
   Permission to use, copy, modify, distribute, and sell this
   software and its documentation for any purpose is hereby granted
 
   Permission to use, copy, modify, distribute, and sell this
   software and its documentation for any purpose is hereby granted
@@ -108,7 +108,17 @@ void Application_Jump_Check(void)
 {
        bool JumpToApplication = false;
 
 {
        bool JumpToApplication = false;
 
-       #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
+       #if (BOARD == BOARD_LEONARDO)
+               /* Enable pull-up on the IO13 pin so we can use it to select the mode */
+               PORTC |= (1 << 7);
+               Delay_MS(10);
+
+               /* If IO13 is not jumpered to ground, start the user application instead */
+               JumpToApplication = ((PINC & (1 << 7)) != 0);
+
+               /* Disable pull-up after the check has completed */
+               PORTC &= ~(1 << 7);
+       #elif ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
                /* Disable JTAG debugging */
                JTAG_DISABLE();
 
                /* Disable JTAG debugging */
                JTAG_DISABLE();
 
@@ -117,21 +127,41 @@ void Application_Jump_Check(void)
                Delay_MS(10);
 
                /* If the TCK pin is not jumpered to ground, start the user application instead */
                Delay_MS(10);
 
                /* If the TCK pin is not jumpered to ground, start the user application instead */
-               JumpToApplication |= ((PINF & (1 << 4)) != 0);
+               JumpToApplication = ((PINF & (1 << 4)) != 0);
 
                /* Re-enable JTAG debugging */
                JTAG_ENABLE();
 
                /* Re-enable JTAG debugging */
                JTAG_ENABLE();
+       #else
+               /* Check if the device's BOOTRST fuse is set */
+               if (!(BootloaderAPI_ReadFuse(GET_HIGH_FUSE_BITS) & ~FUSE_BOOTRST))
+               {
+                       /* If the reset source was not an external reset or the key is correct, clear it and jump to the application */
+                       if (!(MCUSR & (1 << EXTRF)) || (MagicBootKey == MAGIC_BOOT_KEY))
+                         JumpToApplication = true;
+
+                       /* Clear reset source */
+                       MCUSR &= ~(1 << EXTRF);
+               }
+               else
+               {
+                       /* If the reset source was the bootloader and the key is correct, clear it and jump to the application;
+                        * this can happen in the HWBE fuse is set, and the HBE pin is low during the watchdog reset */
+                       if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY))
+                               JumpToApplication = true;
+
+                       /* Clear reset source */
+                       MCUSR &= ~(1 << WDRF);
+               }
        #endif
 
        #endif
 
-       /* 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))
-         JumpToApplication |= true;
+       /* Don't run the user application if the reset vector is blank (no app loaded) */
+       bool ApplicationValid = (pgm_read_word_near(0) != 0xFFFF);
 
        /* If a request has been made to jump to the user application, honor it */
 
        /* If a request has been made to jump to the user application, honor it */
-       if (JumpToApplication)
+       if (JumpToApplication && ApplicationValid)
        {
                /* Turn off the watchdog */
        {
                /* Turn off the watchdog */
-               MCUSR &= ~(1<<WDRF);
+               MCUSR &= ~(1 << WDRF);
                wdt_disable();
 
                /* Clear the boot key and jump to the user application */
                wdt_disable();
 
                /* Clear the boot key and jump to the user application */
@@ -161,6 +191,9 @@ int main(void)
        while (RunBootloader || WaitForExit)
          USB_USBTask();
 
        while (RunBootloader || WaitForExit)
          USB_USBTask();
 
+       /* Wait a short time to end all USB transactions and then disconnect */
+       _delay_us(1000);
+
        /* Reset configured hardware back to their original states for the user application */
        ResetHardware();
 
        /* Reset configured hardware back to their original states for the user application */
        ResetHardware();
 
@@ -321,7 +354,7 @@ void EVENT_USB_Device_ControlRequest(void)
                                                        }
 
                                                        /* Write the next word into the current flash page */
                                                        }
 
                                                        /* Write the next word into the current flash page */
-                                                       boot_page_fill(CurrFlashAddress.Long, Endpoint_Read_16_LE());
+                                                       BootloaderAPI_FillWord(CurrFlashAddress.Long, Endpoint_Read_16_LE());
 
                                                        /* Adjust counters */
                                                        WordsInFlashPage      += 1;
 
                                                        /* Adjust counters */
                                                        WordsInFlashPage      += 1;
@@ -331,8 +364,7 @@ void EVENT_USB_Device_ControlRequest(void)
                                                        if ((WordsInFlashPage == (SPM_PAGESIZE >> 1)) || !(WordsRemaining))
                                                        {
                                                                /* Commit the flash page to memory */
                                                        if ((WordsInFlashPage == (SPM_PAGESIZE >> 1)) || !(WordsRemaining))
                                                        {
                                                                /* Commit the flash page to memory */
-                                                               boot_page_write(CurrFlashPageStartAddress);
-                                                               boot_spm_busy_wait();
+                                                               BootloaderAPI_WritePage(CurrFlashPageStartAddress);
 
                                                                /* Check if programming incomplete */
                                                                if (WordsRemaining)
 
                                                                /* Check if programming incomplete */
                                                                if (WordsRemaining)
@@ -341,17 +373,13 @@ void EVENT_USB_Device_ControlRequest(void)
                                                                        WordsInFlashPage          = 0;
 
                                                                        /* Erase next page's temp buffer */
                                                                        WordsInFlashPage          = 0;
 
                                                                        /* Erase next page's temp buffer */
-                                                                       boot_page_erase(CurrFlashAddress.Long);
-                                                                       boot_spm_busy_wait();
+                                                                       BootloaderAPI_ErasePage(CurrFlashAddress.Long);
                                                                }
                                                        }
                                                }
 
                                                /* Once programming complete, start address equals the end address */
                                                StartAddr = EndAddr;
                                                                }
                                                        }
                                                }
 
                                                /* Once programming complete, start address equals the end address */
                                                StartAddr = EndAddr;
-
-                                               /* Re-enable the RWW section of flash */
-                                               boot_rww_enable();
                                        }
                                        else                                                   // Write EEPROM
                                        {
                                        }
                                        else                                                   // Write EEPROM
                                        {
@@ -370,7 +398,7 @@ void EVENT_USB_Device_ControlRequest(void)
                                                        }
 
                                                        /* Read the byte from the USB interface and write to to the EEPROM */
                                                        }
 
                                                        /* Read the byte from the USB interface and write to to the EEPROM */
-                                                       eeprom_write_byte((uint8_t*)StartAddr, Endpoint_Read_8());
+                                                       eeprom_update_byte((uint8_t*)StartAddr, Endpoint_Read_8());
 
                                                        /* Adjust counters */
                                                        StartAddr++;
 
                                                        /* Adjust counters */
                                                        StartAddr++;
@@ -661,8 +689,7 @@ static void ProcessMemProgCommand(void)
                        } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}};
 
                        /* Erase the current page's temp buffer */
                        } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}};
 
                        /* Erase the current page's temp buffer */
-                       boot_page_erase(CurrFlashAddress.Long);
-                       boot_spm_busy_wait();
+                       BootloaderAPI_ErasePage(CurrFlashAddress.Long);
                }
 
                /* Set the state so that the next DNLOAD requests reads in the firmware */
                }
 
                /* Set the state so that the next DNLOAD requests reads in the firmware */
@@ -751,28 +778,17 @@ static void ProcessWriteCommand(void)
                        }
                        else                                                               // Start via jump
                        {
                        }
                        else                                                               // Start via jump
                        {
-                               /* Set the flag to terminate the bootloader at next opportunity */
-                               RunBootloader = false;
+                               /* Set the flag to terminate the bootloader at next opportunity if a valid application has been loaded */
+                               if (pgm_read_word_near(0) == 0xFFFF)
+                                 RunBootloader = false;
                        }
                }
        }
        else if (IS_TWOBYTE_COMMAND(SentCommand.Data, 0x00, 0xFF))                 // Erase flash
        {
                        }
                }
        }
        else if (IS_TWOBYTE_COMMAND(SentCommand.Data, 0x00, 0xFF))                 // Erase flash
        {
-               uint32_t CurrFlashAddress = 0;
-
                /* Clear the application section of flash */
                /* Clear the application section of flash */
-               while (CurrFlashAddress < (uint32_t)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();
+               for (uint32_t CurrFlashAddress = 0; CurrFlashAddress < (uint32_t)BOOT_START_ADDR; CurrFlashAddress += SPM_PAGESIZE)
+                       BootloaderAPI_ErasePage(CurrFlashAddress);
 
                /* Memory has been erased, reset the security bit so that programming/reading is allowed */
                IsSecure = false;
 
                /* Memory has been erased, reset the security bit so that programming/reading is allowed */
                IsSecure = false;
@@ -787,18 +803,42 @@ static void ProcessReadCommand(void)
        const uint8_t BootloaderInfo[3] = {BOOTLOADER_VERSION, BOOTLOADER_ID_BYTE1, BOOTLOADER_ID_BYTE2};
        const uint8_t SignatureInfo[4]  = {0x58, AVR_SIGNATURE_1, AVR_SIGNATURE_2, AVR_SIGNATURE_3};
 
        const uint8_t BootloaderInfo[3] = {BOOTLOADER_VERSION, BOOTLOADER_ID_BYTE1, BOOTLOADER_ID_BYTE2};
        const uint8_t SignatureInfo[4]  = {0x58, AVR_SIGNATURE_1, AVR_SIGNATURE_2, AVR_SIGNATURE_3};
 
-       uint8_t DataIndexToRead = SentCommand.Data[1];
+       uint8_t DataIndexToRead    = SentCommand.Data[1];
+       bool    ReadAddressInvalid = false;
 
        if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00))                        // Read bootloader info
        {
 
        if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00))                        // Read bootloader info
        {
-               ResponseByte = BootloaderInfo[DataIndexToRead];
+               if (DataIndexToRead < 3)
+                 ResponseByte = BootloaderInfo[DataIndexToRead];
+               else
+                 ReadAddressInvalid = true;
        }
        else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01))                    // Read signature byte
        {
        }
        else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01))                    // Read signature byte
        {
-               if (DataIndexToRead < 0x60)
-                 ResponseByte = SignatureInfo[DataIndexToRead - 0x30];
-               else
-                 ResponseByte = SignatureInfo[DataIndexToRead - 0x60 + 3];
+               switch (DataIndexToRead)
+               {
+                       case 0x30:
+                               ResponseByte = SignatureInfo[0];
+                               break;
+                       case 0x31:
+                               ResponseByte = SignatureInfo[1];
+                               break;
+                       case 0x60:
+                               ResponseByte = SignatureInfo[2];
+                               break;
+                       case 0x61:
+                               ResponseByte = SignatureInfo[3];
+                               break;
+                       default:
+                               ReadAddressInvalid = true;
+                               break;
+               }
        }
        }
-}
 
 
+       if (ReadAddressInvalid)
+       {
+               /* Set the state and status variables to indicate the error */
+               DFU_State  = dfuERROR;
+               DFU_Status = errADDRESS;
+       }
+}