/*
LUFA Library
Copyright (C) Dean Camera, 2010.
-
+
dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
+ www.lufa-lib.org
*/
/*
Copyright 2010 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
uint16_t EndAddr = 0x0000;
-/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously
+/** 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, or hard-reset via the watchdog to start
* the loaded application code.
*/
{
/* Configure hardware required by the bootloader */
SetupHardware();
+
+ #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
+ /* Disable JTAG debugging */
+ MCUCR |= (1 << JTD);
+ MCUCR |= (1 << JTD);
+
+ /* 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 */
+ RunBootloader = (!(PINF & (1 << 4)));
+ /* Re-enable JTAG debugging */
+ MCUCR &= ~(1 << JTD);
+ MCUCR &= ~(1 << JTD);
+ #endif
+
/* Enable global interrupts so that the USB stack can function */
sei();
/* Run the USB management task while the bootloader is supposed to be running */
while (RunBootloader || WaitForExit)
USB_USBTask();
-
+
/* Reset configured hardware back to their original states for the user application */
ResetHardware();
-
+
/* Start the user application */
AppStartPtr();
}
/* Disable clock division */
clock_prescale_set(clock_div_1);
-
+
/* Relocate the interrupt vector table to the bootloader section */
MCUCR = (1 << IVCE);
MCUCR = (1 << IVSEL);
{
/* Shut down the USB subsystem */
USB_ShutDown();
-
+
/* Relocate the interrupt vector table back to the application section */
MCUCR = (1 << IVCE);
MCUCR = 0;
}
-/** Event handler for the USB_UnhandledControlRequest event. This is used to catch standard and class specific
- * control requests that are not handled internally by the USB library (including the DFU commands, which are
- * all issued via the control endpoint), so that they can be handled appropriately for the application.
+/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
+ * the device from the USB host before passing along unhandled control requests to the library for processing
+ * internally.
*/
-void EVENT_USB_Device_UnhandledControlRequest(void)
+void EVENT_USB_Device_ControlRequest(void)
{
/* Get the size of the command and data from the wLength value */
SentCommand.DataSize = USB_ControlRequest.wLength;
+
+ /* Ignore any requests that aren't directed to the DFU interface */
+ if ((USB_ControlRequest.bmRequestType & (CONTROL_REQTYPE_TYPE | CONTROL_REQTYPE_RECIPIENT)) !=
+ (REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ return;
+ }
switch (USB_ControlRequest.bRequest)
{
case REQ_DFU_DNLOAD:
Endpoint_ClearSETUP();
-
+
/* Check if bootloader is waiting to terminate */
if (WaitForExit)
{
/* Bootloader is terminating - process last received command */
ProcessBootloaderCommand();
-
+
/* Indicate that the last command has now been processed - free to exit bootloader */
WaitForExit = false;
}
-
+
/* If the request has a data stage, load it into the command struct */
if (SentCommand.DataSize)
{
while (!(Endpoint_IsOUTReceived()))
- {
+ {
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
/* First byte of the data stage is the DNLOAD request's command */
SentCommand.Command = Endpoint_Read_Byte();
-
+
/* One byte of the data stage is the command, so subtract it from the total data bytes */
SentCommand.DataSize--;
-
+
/* Load in the rest of the data stage as command parameters */
for (uint8_t DataByte = 0; (DataByte < sizeof(SentCommand.Data)) &&
Endpoint_BytesInEndpoint(); DataByte++)
SentCommand.Data[DataByte] = Endpoint_Read_Byte();
SentCommand.DataSize--;
}
-
+
/* Process the command */
ProcessBootloaderCommand();
}
-
+
/* Check if currently downloading firmware */
if (DFU_State == dfuDNLOAD_IDLE)
- {
+ {
if (!(SentCommand.DataSize))
{
DFU_State = dfuIDLE;
/* Throw away the packet alignment filler bytes before the start of the firmware */
DiscardFillerBytes(StartAddr % FIXED_CONTROL_ENDPOINT_SIZE);
-
+
/* Calculate the number of bytes remaining to be written */
uint16_t BytesRemaining = ((EndAddr - StartAddr) + 1);
-
+
if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00)) // Write flash
{
/* Calculate the number of words to be written from the number of bytes to be written */
uint16_t WordsRemaining = (BytesRemaining >> 1);
-
+
union
{
uint16_t Words[2];
uint32_t Long;
} CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}};
-
+
uint32_t CurrFlashPageStartAddress = CurrFlashAddress.Long;
uint8_t WordsInFlashPage = 0;
Endpoint_ClearOUT();
while (!(Endpoint_IsOUTReceived()))
- {
+ {
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
/* Commit the flash page to memory */
boot_page_write(CurrFlashPageStartAddress);
boot_spm_busy_wait();
-
+
/* Check if programming incomplete */
if (WordsRemaining)
{
}
}
}
-
+
/* Once programming complete, start address equals the end address */
StartAddr = EndAddr;
-
+
/* Re-enable the RWW section of flash */
boot_rww_enable();
}
Endpoint_ClearOUT();
while (!(Endpoint_IsOUTReceived()))
- {
+ {
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
/* Read the byte from the USB interface and write to to the EEPROM */
eeprom_write_byte((uint8_t*)StartAddr, Endpoint_Read_Byte());
-
+
/* Adjust counters */
StartAddr++;
}
}
-
+
/* Throw away the currently unused DFU file suffix */
DiscardFillerBytes(DFU_FILE_SUFFIX_SIZE);
}
Endpoint_ClearSETUP();
while (!(Endpoint_IsINReady()))
- {
+ {
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
-
+
if (DFU_State != dfuUPLOAD_IDLE)
{
if ((DFU_State == dfuERROR) && IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01)) // Blank Check
Endpoint_ClearIN();
while (!(Endpoint_IsINReady()))
- {
+ {
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
#if (FLASHEND > 0xFFFF)
Endpoint_Write_Word_LE(pgm_read_word_far(CurrFlashAddress.Long));
#else
- Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long));
+ Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long));
#endif
/* Adjust counters */
CurrFlashAddress.Long += 2;
}
-
+
/* Once reading is complete, start address equals the end address */
StartAddr = EndAddr;
}
if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE)
{
Endpoint_ClearIN();
-
+
while (!(Endpoint_IsINReady()))
- {
+ {
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
break;
case REQ_DFU_GETSTATUS:
Endpoint_ClearSETUP();
-
+
/* Write 8-bit status value */
Endpoint_Write_Byte(DFU_Status);
-
+
/* Write 24-bit poll timeout value */
Endpoint_Write_Byte(0);
Endpoint_Write_Word_LE(0);
-
+
/* Write 8-bit state value */
Endpoint_Write_Byte(DFU_State);
Endpoint_Write_Byte(0);
Endpoint_ClearIN();
-
+
Endpoint_ClearStatusStage();
- break;
+ break;
case REQ_DFU_CLRSTATUS:
Endpoint_ClearSETUP();
-
+
/* Reset the status value variable to the default OK status */
DFU_Status = OK;
break;
case REQ_DFU_GETSTATE:
Endpoint_ClearSETUP();
-
+
/* Write the current device state to the endpoint */
Endpoint_Write_Byte(DFU_State);
-
+
Endpoint_ClearIN();
-
+
Endpoint_ClearStatusStage();
break;
case REQ_DFU_ABORT:
Endpoint_ClearSETUP();
-
+
/* Reset the current state variable to the default idle state */
DFU_State = dfuIDLE;
/* Wait until next data packet received */
while (!(Endpoint_IsOUTReceived()))
- {
+ {
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
/* Set the state and status variables to indicate the error */
DFU_State = dfuERROR;
DFU_Status = errWRITE;
-
+
/* Stall command */
Endpoint_StallTransaction();
-
+
/* Don't process the command */
return;
}
uint16_t Word;
} Address[2] = {{.Bytes = {SentCommand.Data[2], SentCommand.Data[1]}},
{.Bytes = {SentCommand.Data[4], SentCommand.Data[3]}}};
-
+
/* Load in the start and ending read addresses from the sent data packet */
StartAddr = Address[0].Word;
EndAddr = Address[1].Word;
{
/* Load in the start and ending read addresses */
LoadStartEndAddresses();
-
+
/* If FLASH is being written to, we need to pre-erase the first page to write to */
if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00))
{
uint16_t Words[2];
uint32_t Long;
} CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}};
-
+
/* Erase the current page's temp buffer */
boot_page_erase(CurrFlashAddress.Long);
boot_spm_busy_wait();
}
-
+
/* Set the state so that the next DNLOAD requests reads in the firmware */
DFU_State = dfuDNLOAD_IDLE;
}
/* Save the location of the first non-blank byte for response back to the host */
Flash64KBPage = (CurrFlashAddress >> 16);
StartAddr = CurrFlashAddress;
-
+
/* Set state and status variables to the appropriate error values */
DFU_State = dfuERROR;
DFU_Status = errCHECK_ERASED;
/* Re-enable the RWW section of flash as writing to the flash locks it out */
boot_rww_enable();
-
+
/* Memory has been erased, reset the security bit so that programming/reading is allowed */
IsSecure = false;
}
else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01)) // Read signature byte
ResponseByte = SignatureInfo[DataIndexToRead - 0x30];
}
+