X-Git-Url: http://git.linex4red.de/pub/lufa.git/blobdiff_plain/7b5b8f199f0290d2befcde56fb99fe68c61d15ff..refs/heads/ProMicro:/Bootloaders/Printer/BootloaderPrinter.c?ds=sidebyside diff --git a/Bootloaders/Printer/BootloaderPrinter.c b/Bootloaders/Printer/BootloaderPrinter.c index b80c08284..15f834ad6 100644 --- a/Bootloaders/Printer/BootloaderPrinter.c +++ b/Bootloaders/Printer/BootloaderPrinter.c @@ -1,13 +1,13 @@ /* LUFA Library - Copyright (C) Dean Camera, 2013. + Copyright (C) Dean Camera, 2021. dean [at] fourwalledcubicle [dot] com www.lufa-lib.org */ /* - Copyright 2013 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 @@ -43,7 +43,7 @@ USB_ClassInfo_PRNT_Device_t TextOnly_Printer_Interface = { .Config = { - .InterfaceNumber = 0, + .InterfaceNumber = INTERFACE_ID_Printer, .DataINEndpoint = { .Address = PRINTER_IN_EPADDR, @@ -67,7 +67,7 @@ USB_ClassInfo_PRNT_Device_t TextOnly_Printer_Interface = /** Intel HEX parser state machine state information, to track the contents of * a HEX file streamed in as a sequence of arbitrary bytes. */ -struct +static struct { /** Current HEX parser state machine state. */ uint8_t ParserState; @@ -87,22 +87,18 @@ struct /** Checksum of the current record received so far. */ uint8_t Checksum; /** Starting address of the last addressed FLASH page. */ - uint32_t PageStartAddress; + flashaddr_t PageStartAddress; /** Current 32-bit byte extended base address in FLASH being targeted. */ - uint32_t CurrBaseAddress; + flashaddr_t CurrBaseAddress; /** Current 32-bit byte address in FLASH being targeted. */ - uint32_t CurrAddress; -} HEXParser = - { - .ParserState = HEX_PARSE_STATE_WAIT_LINE - }; + flashaddr_t CurrAddress; +} 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 (!(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 + + /* 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 @@ -154,6 +206,30 @@ static int8_t HexToDecimal(const char Byte) } /** + * 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) + { + BootloaderAPI_WritePage(HEXParser.PageStartAddress); + + HEXParser.PageStartAddress = NewPageStartAddress; + + PageDirty = false; + } +} + +/** * Parses an input Intel HEX formatted stream one character at a time, loading * the data contents into the device's internal FLASH memory. * @@ -241,32 +317,20 @@ 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); - boot_spm_busy_wait(); + BootloaderAPI_ErasePage(HEXParser.PageStartAddress); PageDirty = true; } /* Fill the FLASH memory buffer with the new word of data */ - boot_page_fill(HEXParser.CurrAddress, NewDataWord); + BootloaderAPI_FillWord(HEXParser.CurrAddress, NewDataWord); 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: @@ -290,16 +354,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) @@ -346,6 +401,9 @@ int main(void) USB_USBTask(); } + /* Wait a short time to end all USB transactions and then disconnect */ + _delay_us(1000); + /* Disconnect from the host - USB interface will be reset later along with the AVR */ USB_Detach(); @@ -413,6 +471,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); }