Add automatic application start on virtual disk ejection to the Mass Storage class...
authorDean Camera <dean@fourwalledcubicle.com>
Sat, 6 Jul 2013 10:26:33 +0000 (12:26 +0200)
committerDean Camera <dean@fourwalledcubicle.com>
Sat, 6 Jul 2013 10:26:33 +0000 (12:26 +0200)
Bootloaders/MassStorage/BootloaderMassStorage.c
Bootloaders/MassStorage/BootloaderMassStorage.h
Bootloaders/MassStorage/BootloaderMassStorage.txt
Bootloaders/MassStorage/Config/AppConfig.h [new file with mode: 0644]
Bootloaders/MassStorage/Lib/SCSI.c
Bootloaders/MassStorage/Lib/SCSI.h
LUFA/Build/lufa_core.mk

index 28f42b6..1b6eda4 100644 (file)
@@ -33,6 +33,7 @@
  *  Main source file for the Mass Storage class bootloader. This file contains the complete bootloader logic.
  */
 
  *  Main source file for the Mass Storage class bootloader. This file contains the complete bootloader logic.
  */
 
+#define  INCLUDE_FROM_BOOTLOADER_MASSSTORAGE_C
 #include "BootloaderMassStorage.h"
 
 /** LUFA Mass Storage Class driver interface configuration and state information. This structure is
 #include "BootloaderMassStorage.h"
 
 /** LUFA Mass Storage Class driver interface configuration and state information. This structure is
@@ -60,7 +61,30 @@ USB_ClassInfo_MS_Device_t Disk_MS_Interface =
                        },
        };
 
                        },
        };
 
+/** 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
+ *  started via a forced watchdog reset.
+ */
+bool RunBootloader = true;
+
+/** 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;
+
+/** Indicates if the bootloader is allowed to exit immediately if \ref RunBootloader is \c false. During shutdown all
+ *  pending commands must be processed before jumping to the user-application, thus this tracks the main program loop
+ *  iterations since a SCSI command from the host was received.
+ */
+static uint8_t TicksSinceLastCommand = 0;
+
 
 
+/** 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)
 {
        bool JumpToApplication = false;
 void Application_Jump_Check(void)
 {
        bool JumpToApplication = false;
@@ -90,6 +114,13 @@ void Application_Jump_Check(void)
                JTAG_ENABLE();
        #endif
 
                JTAG_ENABLE();
        #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))
+       {
+               MagicBootKey      = 0;
+               JumpToApplication = true;
+       }
+
        if (JumpToApplication)
        {
                // cppcheck-suppress constStatement
        if (JumpToApplication)
        {
                // cppcheck-suppress constStatement
@@ -107,11 +138,22 @@ int main(void)
        LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
        GlobalInterruptEnable();
 
        LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
        GlobalInterruptEnable();
 
-       for (;;)
+       while (RunBootloader || TicksSinceLastCommand++ < 0xFF)
        {
                MS_Device_USBTask(&Disk_MS_Interface);
                USB_USBTask();
        }
        {
                MS_Device_USBTask(&Disk_MS_Interface);
                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);
+
+       for (;;);
 }
 
 /** Configures the board hardware and chip peripherals for the demo's functionality. */
 }
 
 /** Configures the board hardware and chip peripherals for the demo's functionality. */
@@ -189,5 +231,8 @@ bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSI
        CommandSuccess = SCSI_DecodeSCSICommand(MSInterfaceInfo);
        LEDs_SetAllLEDs(LEDMASK_USB_READY);
 
        CommandSuccess = SCSI_DecodeSCSICommand(MSInterfaceInfo);
        LEDs_SetAllLEDs(LEDMASK_USB_READY);
 
+       /* Signal that a command was processed, must not exit bootloader yet */
+       TicksSinceLastCommand = 0;
+
        return CommandSuccess;
 }
        return CommandSuccess;
 }
index 1fcce90..d8271ea 100644 (file)
@@ -44,6 +44,7 @@
                #include <string.h>
 
                #include "Descriptors.h"
                #include <string.h>
 
                #include "Descriptors.h"
+               #include "Config/AppConfig.h"
 
                #include "Lib/SCSI.h"
 
 
                #include "Lib/SCSI.h"
 
                /** LED mask for the library LED driver, to indicate that the USB interface is busy. */
                #define LEDMASK_USB_BUSY          LEDS_LED2
 
                /** LED mask for the library LED driver, to indicate that the USB interface is busy. */
                #define LEDMASK_USB_BUSY          LEDS_LED2
 
+               /** Magic bootloader key to unlock forced application start mode. */
+               #define MAGIC_BOOT_KEY             0xDC42
+
+       /* Global Variables: */
+               extern bool RunBootloader;
+
        /* Function Prototypes: */
                int main(void) AUX_BOOT_SECTION;
 
        /* Function Prototypes: */
                int main(void) AUX_BOOT_SECTION;
 
-               static void SetupHardware(void) AUX_BOOT_SECTION;
-
                void Application_Jump_Check(void) ATTR_INIT_SECTION(3);
 
                void EVENT_USB_Device_Connect(void) AUX_BOOT_SECTION;
                void Application_Jump_Check(void) ATTR_INIT_SECTION(3);
 
                void EVENT_USB_Device_Connect(void) AUX_BOOT_SECTION;
@@ -86,5 +91,9 @@
 
                bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) AUX_BOOT_SECTION;
 
 
                bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) AUX_BOOT_SECTION;
 
+               #if defined(INCLUDE_FROM_BOOTLOADER_MASSSTORAGE_C)
+                       static void SetupHardware(void) AUX_BOOT_SECTION;
+               #endif
+
 #endif
 
 #endif
 
index 85cbc6f..f7b3038 100644 (file)
  *
  *  <table>
  *   <tr>
  *
  *  <table>
  *   <tr>
- *    <td>
- *     None
- *    </td>
+ *    <th><b>Define Name:</b></th>
+ *    <th><b>Location:</b></th>
+ *    <th><b>Description:</b></th>
+ *   </tr>
+ *   <tr>
+ *    <td>NO_APP_START_ON_EJECT</td>
+ *    <td>AppConfig.h</td>
+ *    <td>Define to disable automatic start of the loaded application when the virtual
+ *        Mass Storage disk is ejected on the host.</td>
  *   </tr>
  *  </table>
  */
  *   </tr>
  *  </table>
  */
diff --git a/Bootloaders/MassStorage/Config/AppConfig.h b/Bootloaders/MassStorage/Config/AppConfig.h
new file mode 100644 (file)
index 0000000..ada2371
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2013.
+
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2013  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
+  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
+  software without specific, written prior permission.
+
+  The author disclaims 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
+ *  \brief Application Configuration Header File
+ *
+ *  This is a header file which is be used to configure LUFA's
+ *  compile time options, as an alternative to the compile time
+ *  constants supplied through a makefile.
+ *
+ *  For information on what each token does, refer to the
+ *  \ref Sec_Options section of the application documentation.
+ */
+
+#ifndef _APP_CONFIG_H_
+#define _APP_CONFIG_H_
+
+//     #define NO_APP_START_ON_EJECT
+
+#endif
index eeb2c25..3bb868c 100644 (file)
@@ -113,8 +113,12 @@ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
                case SCSI_CMD_MODE_SENSE_6:
                        CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
                        break;
                case SCSI_CMD_MODE_SENSE_6:
                        CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
                        break;
-               case SCSI_CMD_SEND_DIAGNOSTIC:
                case SCSI_CMD_START_STOP_UNIT:
                case SCSI_CMD_START_STOP_UNIT:
+#if !defined(NO_APP_START_ON_EJECT)
+                       /* If the user ejected the volume, signal bootloader exit at next opportunity. */
+                       RunBootloader = ((MSInterfaceInfo->State.CommandBlock.SCSICommandData[4] & 0x03) != 0x02);
+#endif
+               case SCSI_CMD_SEND_DIAGNOSTIC:
                case SCSI_CMD_TEST_UNIT_READY:
                case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
                case SCSI_CMD_VERIFY_10:
                case SCSI_CMD_TEST_UNIT_READY:
                case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
                case SCSI_CMD_VERIFY_10:
index 8eb817f..afed5a6 100644 (file)
@@ -42,6 +42,7 @@
 
                #include <LUFA/Drivers/USB/USB.h>
 
 
                #include <LUFA/Drivers/USB/USB.h>
 
+               #include "../BootloaderMassStorage.h"
                #include "../Descriptors.h"
                #include "VirtualFAT.h"
 
                #include "../Descriptors.h"
                #include "VirtualFAT.h"
 
index 914a939..11bf65c 100644 (file)
@@ -131,7 +131,7 @@ help:
        @printf " %b" "$(PRINTABLE_LUFA_PROVIDED_MACROS:%=   - %\n)"
        @echo "                                                                   "
        @echo "==================================================================="
        @printf " %b" "$(PRINTABLE_LUFA_PROVIDED_MACROS:%=   - %\n)"
        @echo "                                                                   "
        @echo "==================================================================="
-       @echo "        The LUFA BuildSystem 2.0 - Powered By Duct Tape (tm)       "
+       @echo "   The LUFA BuildSystem 2.0 - Powered By Positive Thinking (tm)    "
        @echo "==================================================================="
 
 # Lists build modules included by the project makefile, in alphabetical order
        @echo "==================================================================="
 
 # Lists build modules included by the project makefile, in alphabetical order