Mark build test makefiles as being incompatible with parallel make builds, as they...
[pub/USBasp.git] / Bootloaders / HID / BootloaderHID.c
index f4cb0f1..c32dddc 100644 (file)
@@ -1,21 +1,21 @@
 /*
              LUFA Library
-     Copyright (C) Dean Camera, 2011.
+     Copyright (C) Dean Camera, 2012.
 
   dean [at] fourwalledcubicle [dot] com
            www.lufa-lib.org
 */
 
 /*
-  Copyright 2011  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+  Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com)
 
-  Permission to use, copy, modify, distribute, and sell this 
+  Permission to use, copy, modify, distribute, and sell this
   software and its documentation for any purpose is hereby granted
-  without fee, provided that the above copyright notice appear in 
+  without fee, provided that the above copyright notice appear in
   all copies and that both that the copyright notice and this
-  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 
+  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
   software without specific, written prior permission.
 
   The author disclaim all warranties with regard to this
@@ -32,7 +32,7 @@
  *
  *  Main source file for the HID class bootloader. This file contains the complete bootloader logic.
  */
+
 #include "BootloaderHID.h"
 
 /** Flag to indicate if the bootloader should be running, or should exit and allow the application code to run
  */
 static bool RunBootloader = true;
 
-/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously 
+/** 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.
+ */
+uint16_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;
+               // cppcheck-suppress constStatement
+               ((void (*)(void))0x0000)();
+       }
+}
+
+/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously
  *  runs the bootloader processing routine until instructed to soft-exit.
  */
 int main(void)
 {
        /* Setup hardware required for the bootloader */
        SetupHardware();
-       
+
        /* Enable global interrupts so that the USB stack can function */
        sei();
 
        while (RunBootloader)
          USB_USBTask();
-       
+
        /* Disconnect from the host - USB interface will be reset later along with the AVR */
        USB_Detach();
 
+       /* Unlock the forced application start mode of the bootloader if it is restarted */
+       MagicBootKey = MAGIC_BOOT_KEY;
+
        /* Enable the watchdog and force a timeout to reset the AVR */
        wdt_enable(WDTO_250MS);
 
@@ -65,7 +91,7 @@ int main(void)
 }
 
 /** Configures all hardware required for the bootloader. */
-void SetupHardware(void)
+static void SetupHardware(void)
 {
        /* Disable watchdog if enabled by bootloader/fuses */
        MCUSR &= ~(1 << WDRF);
@@ -85,9 +111,7 @@ void SetupHardware(void)
 void EVENT_USB_Device_ConfigurationChanged(void)
 {
        /* Setup HID Report Endpoint */
-       Endpoint_ConfigureEndpoint(HID_IN_EPNUM, EP_TYPE_INTERRUPT,
-                                      ENDPOINT_DIR_IN, HID_IN_EPSIZE,
-                                  ENDPOINT_BANK_SINGLE);
+       Endpoint_ConfigureEndpoint(HID_IN_EPADDR, EP_TYPE_INTERRUPT, HID_IN_EPSIZE, 1);
 }
 
 /** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
@@ -108,17 +132,17 @@ void EVENT_USB_Device_ControlRequest(void)
        {
                case HID_REQ_SetReport:
                        Endpoint_ClearSETUP();
-                       
+
                        /* Wait until the command has been sent by the host */
                        while (!(Endpoint_IsOUTReceived()));
-               
+
                        /* Read in the write destination address */
                        #if (FLASHEND > 0xFFFF)
                        uint32_t PageAddress = ((uint32_t)Endpoint_Read_16_LE() << 8);
                        #else
                        uint16_t PageAddress = Endpoint_Read_16_LE();
                        #endif
-                       
+
                        /* Check if the command is a program page command, or a start application command */
                        #if (FLASHEND > 0xFFFF)
                        if ((uint16_t)(PageAddress >> 8) == COMMAND_STARTAPPLICATION)
@@ -133,9 +157,9 @@ void EVENT_USB_Device_ControlRequest(void)
                                /* Erase the given FLASH page, ready to be programmed */
                                boot_page_erase(PageAddress);
                                boot_spm_busy_wait();
-                               
+
                                /* Write each of the FLASH page's bytes in sequence */
-                               for (uint8_t PageWord = 0; PageWord < (SPM_PAGESIZE / 2); PageWord++)                           
+                               for (uint8_t PageWord = 0; PageWord < (SPM_PAGESIZE / 2); PageWord++)
                                {
                                        /* Check if endpoint is empty - if so clear it and wait until ready for next packet */
                                        if (!(Endpoint_BytesInEndpoint()))
@@ -162,3 +186,4 @@ void EVENT_USB_Device_ControlRequest(void)
                        break;
        }
 }
+