Update Studio Integration DLL, to include package logging.
[pub/USBasp.git] / Bootloaders / Printer / BootloaderPrinter.c
index 023ec3e..aaf3ef1 100644 (file)
@@ -1,13 +1,13 @@
 /*
              LUFA Library
-     Copyright (C) Dean Camera, 2013.
+     Copyright (C) Dean Camera, 2015.
 
   dean [at] fourwalledcubicle [dot] com
            www.lufa-lib.org
 */
 
 /*
-  Copyright 2013  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+  Copyright 2015  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
@@ -43,7 +43,7 @@ USB_ClassInfo_PRNT_Device_t TextOnly_Printer_Interface =
        {
                .Config =
                        {
-                               .InterfaceNumber          = 0,
+                               .InterfaceNumber          = INTERFACE_ID_Printer,
                                .DataINEndpoint           =
                                        {
                                                .Address          = PRINTER_IN_EPADDR,
@@ -92,17 +92,13 @@ struct
        uint32_t CurrBaseAddress;
        /** Current 32-bit byte address in FLASH being targeted. */
        uint32_t CurrAddress;
-} HEXParser =
-       {
-               .ParserState = HEX_PARSE_STATE_WAIT_LINE
-       };
+} HEXParser;
 
 /** Indicates if there is data waiting to be written to a physical page of
  *  memory in FLASH.
  */
 static bool PageDirty = false;
 
-
 /** 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.
@@ -123,9 +119,65 @@ uint16_t MagicBootKey ATTR_NO_INIT;
  */
 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))
+       bool JumpToApplication = false;
+
+       #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();
+
+               /* Enable pull-up on the JTAG TCK pin so we can use it to select the mode */
+               PORTF |= (1 << 4);
+               Delay_MS(10);
+
+               /* If the TCK pin is not jumpered to ground, start the user application instead */
+               JumpToApplication = ((PINF & (1 << 4)) != 0);
+
+               /* Re-enable JTAG debugging */
+               JTAG_ENABLE();
+       #else
+               /* Check if the device's BOOTRST fuse is set */
+               if (boot_lock_fuse_bits_get(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
+
+       /* 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 (JumpToApplication && ApplicationValid)
        {
+               /* Turn off the watchdog */
+               MCUSR &= ~(1 << WDRF);
+               wdt_disable();
+
+               /* Clear the boot key and jump to the user application */
                MagicBootKey = 0;
 
                // cppcheck-suppress constStatement
@@ -134,37 +186,48 @@ void Application_Jump_Check(void)
 }
 
 /**
- * Determines if a given input byte of data is an ASCII encoded HEX value.
- *
- * \note Input HEX bytes are expected to be in uppercase only.
- *
- * \param[in] Byte  ASCII byte of data to check
- *
- * \return Boolean \c true if the input data is ASCII encoded HEX, \c false otherwise.
- */
-static bool IsHex(const char Byte)
-{
-       return ((Byte >= 'A') && (Byte <= 'F')) ||
-              ((Byte >= '0') && (Byte <= '9'));
-}
-
-/**
  * Converts a given input byte of data from an ASCII encoded HEX value to an integer value.
  *
  * \note Input HEX bytes are expected to be in uppercase only.
  *
  * \param[in] Byte  ASCII byte of data to convert
  *
- * \return Integer converted value of the input ASCII encoded HEX byte of data.
+ * \return Integer converted value of the input ASCII encoded HEX byte of data, or -1 if the
+ *         input is not valid ASCII encoded HEX.
  */
-static uint8_t HexToDecimal(const char Byte)
+static int8_t HexToDecimal(const char Byte)
 {
        if ((Byte >= 'A') && (Byte <= 'F'))
          return (10 + (Byte - 'A'));
        else if ((Byte >= '0') && (Byte <= '9'))
          return (Byte - '0');
 
-       return 0;
+       return -1;
+}
+
+/**
+ * Flushes a partially written page of data to physical FLASH, if a page
+ * boundary has been crossed.
+ *
+ * \note If a page flush occurs the global HEX parser state is updated.
+ */
+static void FlushPageIfRequired(void)
+{
+       /* Abort if no data has been buffered for writing to the current page */
+       if (!PageDirty)
+         return;
+
+       /* Flush the FLASH page to physical memory if we are crossing a page boundary */
+       uint32_t NewPageStartAddress = (HEXParser.CurrAddress & ~(SPM_PAGESIZE - 1));
+       if (HEXParser.PageStartAddress != NewPageStartAddress)
+       {
+               boot_page_write(HEXParser.PageStartAddress);
+               boot_spm_busy_wait();
+
+               HEXParser.PageStartAddress = NewPageStartAddress;
+
+               PageDirty = false;
+       }
 }
 
 /**
@@ -180,7 +243,6 @@ static void ParseIntelHEXByte(const char ReadCharacter)
        {
                HEXParser.Checksum     = 0;
                HEXParser.CurrAddress  = HEXParser.CurrBaseAddress;
-               HEXParser.ParserState  = HEX_PARSE_STATE_WAIT_LINE;
                HEXParser.ReadMSB      = false;
 
                /* ASCII ':' indicates the start of a new HEX record */
@@ -191,11 +253,12 @@ static void ParseIntelHEXByte(const char ReadCharacter)
        }
 
        /* Only allow ASCII HEX encoded digits, ignore all other characters */
-       if (!IsHex(ReadCharacter))
+       int8_t ReadCharacterDec = HexToDecimal(ReadCharacter);
+       if (ReadCharacterDec < 0)
          return;
 
        /* Read and convert the next nibble of data from the current character */
-       HEXParser.Data    = (HEXParser.Data << 4) | HexToDecimal(ReadCharacter);
+       HEXParser.Data    = (HEXParser.Data << 4) | ReadCharacterDec;
        HEXParser.ReadMSB = !HEXParser.ReadMSB;
 
        /* Only process further when a full byte (two nibbles) have been read */
@@ -255,9 +318,7 @@ static void ParseIntelHEXByte(const char ReadCharacter)
                        switch (HEXParser.RecordType)
                        {
                                case HEX_RECORD_TYPE_Data:
-                                       /* If we are writing to a new page, we need to erase it
-                                        * first
-                                        */
+                                       /* If we are writing to a new page, we need to erase it first */
                                        if (!(PageDirty))
                                        {
                                                boot_page_erase(HEXParser.PageStartAddress);
@@ -271,16 +332,7 @@ static void ParseIntelHEXByte(const char ReadCharacter)
                                        HEXParser.CurrAddress += 2;
 
                                        /* Flush the FLASH page to physical memory if we are crossing a page boundary */
-                                       uint32_t NewPageStartAddress = (HEXParser.CurrAddress & ~(SPM_PAGESIZE - 1));
-                                       if (PageDirty && (HEXParser.PageStartAddress != NewPageStartAddress))
-                                       {
-                                               boot_page_write(HEXParser.PageStartAddress);
-                                               boot_spm_busy_wait();
-
-                                               HEXParser.PageStartAddress = NewPageStartAddress;
-
-                                               PageDirty = false;
-                                       }
+                                       FlushPageIfRequired();
                                        break;
 
                                case HEX_RECORD_TYPE_ExtendedSegmentAddress:
@@ -304,16 +356,7 @@ static void ParseIntelHEXByte(const char ReadCharacter)
                          break;
 
                        /* Flush the FLASH page to physical memory if we are crossing a page boundary */
-                       uint32_t NewPageStartAddress = (HEXParser.CurrAddress & ~(SPM_PAGESIZE - 1));
-                       if (PageDirty && (HEXParser.PageStartAddress != NewPageStartAddress))
-                       {
-                               boot_page_write(HEXParser.PageStartAddress);
-                               boot_spm_busy_wait();
-
-                               HEXParser.PageStartAddress = NewPageStartAddress;
-
-                               PageDirty = false;
-                       }
+                       FlushPageIfRequired();
 
                        /* If end of the HEX file reached, the bootloader should exit at next opportunity */
                        if (HEXParser.RecordType == HEX_RECORD_TYPE_EndOfFile)
@@ -427,6 +470,9 @@ void EVENT_USB_Device_ConfigurationChanged(void)
        /* Setup Printer Data Endpoints */
        ConfigSuccess &= PRNT_Device_ConfigureEndpoints(&TextOnly_Printer_Interface);
 
+       /* Reset the HEX parser upon successful connection to a host */
+       HEXParser.ParserState = HEX_PARSE_STATE_WAIT_LINE;
+
        /* Indicate endpoint configuration success or failure */
        LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
 }