Update UC3 platform driver support to use the bitmasks defined in the header files...
[pub/USBasp.git] / Bootloaders / DFU / BootloaderDFU.c
index 6f8acc8..1dae162 100644 (file)
@@ -1,21 +1,21 @@
 /*
              LUFA Library
-     Copyright (C) Dean Camera, 2010.
-              
+     Copyright (C) Dean Camera, 2011.
+
   dean [at] fourwalledcubicle [dot] com
-      www.fourwalledcubicle.com
+           www.lufa-lib.org
 */
 
 /*
-  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+  Copyright 2011  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
 
 /** Flag to indicate if the bootloader is currently running in secure mode, disallowing memory operations
  *  other than erase. This is initially set to the value set by SECURE_MODE, and cleared by the bootloader
- *  once a memory erase has completed.
+ *  once a memory erase has completed in a bootloader session.
  */
-bool IsSecure      = SECURE_MODE;
+static bool IsSecure = SECURE_MODE;
 
 /** 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
  *  jumped to via an indirect jump to location 0x0000 (or other location specified by the host).
  */
-bool RunBootloader = true;
+static bool RunBootloader = true;
 
 /** Flag to indicate if the bootloader is waiting to exit. When the host requests the bootloader to exit and
  *  jump to the application address it specifies, it sends two sequential commands which must be properly
  *  acknowledged. Upon reception of the first the RunBootloader flag is cleared and the WaitForExit flag is set,
  *  causing the bootloader to wait for the final exit command before shutting down.
  */
-bool WaitForExit = false;
+static bool WaitForExit = false;
 
 /** Current DFU state machine state, one of the values in the DFU_State_t enum. */
-uint8_t DFU_State = dfuIDLE;
+static uint8_t DFU_State = dfuIDLE;
 
 /** Status code of the last executed DFU command. This is set to one of the values in the DFU_Status_t enum after
  *  each operation, and returned to the host when a Get Status DFU request is issued.
  */
-uint8_t DFU_Status = OK;
+static uint8_t DFU_Status = OK;
 
 /** Data containing the DFU command sent from the host. */
-DFU_Command_t SentCommand;
+static DFU_Command_t SentCommand;
 
 /** Response to the last issued Read Data DFU command. Unlike other DFU commands, the read command
  *  requires a single byte response from the bootloader containing the read data when the next DFU_UPLOAD command
  *  is issued by the host.
  */
-uint8_t ResponseByte;
+static uint8_t ResponseByte;
 
 /** Pointer to the start of the user application. By default this is 0x0000 (the reset vector), however the host
  *  may specify an alternate address when issuing the application soft-start command.
  */
-AppPtr_t AppStartPtr = (AppPtr_t)0x0000;
+static AppPtr_t AppStartPtr = (AppPtr_t)0x0000;
 
 /** 64-bit flash page number. This is concatenated with the current 16-bit address on USB AVRs containing more than
  *  64KB of flash memory.
  */
-uint8_t Flash64KBPage = 0;
+static uint8_t Flash64KBPage = 0;
 
 /** Memory start address, indicating the current address in the memory being addressed (either FLASH or EEPROM
  *  depending on the issued command from the host).
  */
-uint16_t StartAddr = 0x0000;
+static uint16_t StartAddr = 0x0000;
 
-/** Memory end address, indicating the end address to read to/write from in the memory being addressed (either FLASH
+/** Memory end address, indicating the end address to read from/write to in the memory being addressed (either FLASH
  *  of EEPROM depending on the issued command from the host).
  */
-uint16_t EndAddr = 0x0000;
+static 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.
  */
@@ -101,17 +101,37 @@ int main(void)
 {
        /* 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
+
+       /* Turn on first LED on the board to indicate that the bootloader has started */
+       LEDs_SetAllLEDs(LEDS_LED1);
+
        /* 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();
 }
@@ -125,80 +145,101 @@ void SetupHardware(void)
 
        /* Disable clock division */
        clock_prescale_set(clock_div_1);
-       
+
        /* Relocate the interrupt vector table to the bootloader section */
        MCUCR = (1 << IVCE);
        MCUCR = (1 << IVSEL);
 
        /* Initialize the USB subsystem */
        USB_Init();
+       LEDs_Init();
+       
+       /* Bootloader active LED toggle timer initialization */
+       TIMSK1 = (1 << TOIE1);
+       TCCR1B = ((1 << CS11) | (1 << CS10));
 }
 
 /** Resets all configured hardware required for the bootloader back to their original states. */
 void ResetHardware(void)
 {
        /* Shut down the USB subsystem */
-       USB_ShutDown();
-       
+       USB_Disable();
+
        /* 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.
- */
-void EVENT_USB_Device_UnhandledControlRequest(void)
+/** ISR to periodically toggle the LEDs on the board to indicate that the bootloader is active. */
+ISR(TIMER1_OVF_vect, ISR_BLOCK)
 {
+       LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2);
+}
+
+/** 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_ControlRequest(void)
+{      
+       /* 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;
+       }
+
+       /* Activity - toggle indicator LEDs */
+       LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2);
+
        /* Get the size of the command and data from the wLength value */
        SentCommand.DataSize = USB_ControlRequest.wLength;
 
        switch (USB_ControlRequest.bRequest)
        {
-               case REQ_DFU_DNLOAD:
+               case DFU_REQ_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();
-                                       
+                               SentCommand.Command = Endpoint_Read_8();
+
                                /* 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.Data[DataByte] = Endpoint_Read_8();
                                        SentCommand.DataSize--;
                                }
-                               
+
                                /* Process the command */
                                ProcessBootloaderCommand();
                        }
-                       
+
                        /* Check if currently downloading firmware */
                        if (DFU_State == dfuDNLOAD_IDLE)
-                       {                                                                       
+                       {
                                if (!(SentCommand.DataSize))
                                {
                                        DFU_State = dfuIDLE;
@@ -210,21 +251,21 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
 
                                        /* 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;
 
@@ -236,14 +277,14 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                                Endpoint_ClearOUT();
 
                                                                while (!(Endpoint_IsOUTReceived()))
-                                                               {                               
+                                                               {
                                                                        if (USB_DeviceState == DEVICE_STATE_Unattached)
                                                                          return;
                                                                }
                                                        }
 
                                                        /* Write the next word into the current flash page */
-                                                       boot_page_fill(CurrFlashAddress.Long, Endpoint_Read_Word_LE());
+                                                       boot_page_fill(CurrFlashAddress.Long, Endpoint_Read_16_LE());
 
                                                        /* Adjust counters */
                                                        WordsInFlashPage      += 1;
@@ -255,7 +296,7 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                                /* Commit the flash page to memory */
                                                                boot_page_write(CurrFlashPageStartAddress);
                                                                boot_spm_busy_wait();
-                                                               
+
                                                                /* Check if programming incomplete */
                                                                if (WordsRemaining)
                                                                {
@@ -268,10 +309,10 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                                }
                                                        }
                                                }
-                                       
+
                                                /* Once programming complete, start address equals the end address */
                                                StartAddr = EndAddr;
-                                       
+
                                                /* Re-enable the RWW section of flash */
                                                boot_rww_enable();
                                        }
@@ -285,20 +326,20 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                                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());
-                                                       
+                                                       eeprom_write_byte((uint8_t*)StartAddr, Endpoint_Read_8());
+
                                                        /* Adjust counters */
                                                        StartAddr++;
                                                }
                                        }
-                                       
+
                                        /* Throw away the currently unused DFU file suffix */
                                        DiscardFillerBytes(DFU_FILE_SUFFIX_SIZE);
                                }
@@ -309,27 +350,27 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                        Endpoint_ClearStatusStage();
 
                        break;
-               case REQ_DFU_UPLOAD:
+               case DFU_REQ_UPLOAD:
                        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
                                {
                                        /* Blank checking is performed in the DFU_DNLOAD request - if we get here we've told the host
                                           that the memory isn't blank, and the host is requesting the first non-blank address */
-                                       Endpoint_Write_Word_LE(StartAddr);
+                                       Endpoint_Write_16_LE(StartAddr);
                                }
                                else
                                {
                                        /* Idle state upload - send response to last issued command */
-                                       Endpoint_Write_Byte(ResponseByte);
+                                       Endpoint_Write_8(ResponseByte);
                                }
                        }
                        else
@@ -356,7 +397,7 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                        Endpoint_ClearIN();
 
                                                        while (!(Endpoint_IsINReady()))
-                                                       {                               
+                                                       {
                                                                if (USB_DeviceState == DEVICE_STATE_Unattached)
                                                                  return;
                                                        }
@@ -364,15 +405,15 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
 
                                                /* Read the flash word and send it via USB to the host */
                                                #if (FLASHEND > 0xFFFF)
-                                                       Endpoint_Write_Word_LE(pgm_read_word_far(CurrFlashAddress.Long));
+                                                       Endpoint_Write_16_LE(pgm_read_word_far(CurrFlashAddress.Long));
                                                #else
-                                                       Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long));                                                   
+                                                       Endpoint_Write_16_LE(pgm_read_word(CurrFlashAddress.Long));
                                                #endif
 
                                                /* Adjust counters */
                                                CurrFlashAddress.Long += 2;
                                        }
-                                       
+
                                        /* Once reading is complete, start address equals the end address */
                                        StartAddr = EndAddr;
                                }
@@ -384,16 +425,16 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
                                                if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE)
                                                {
                                                        Endpoint_ClearIN();
-                                                       
+
                                                        while (!(Endpoint_IsINReady()))
-                                                       {                               
+                                                       {
                                                                if (USB_DeviceState == DEVICE_STATE_Unattached)
                                                                  return;
                                                        }
                                                }
 
                                                /* Read the EEPROM byte and send it via USB to the host */
-                                               Endpoint_Write_Byte(eeprom_read_byte((uint8_t*)StartAddr));
+                                               Endpoint_Write_8(eeprom_read_byte((uint8_t*)StartAddr));
 
                                                /* Adjust counters */
                                                StartAddr++;
@@ -408,47 +449,47 @@ void EVENT_USB_Device_UnhandledControlRequest(void)
 
                        Endpoint_ClearStatusStage();
                        break;
-               case REQ_DFU_GETSTATUS:
+               case DFU_REQ_GETSTATUS:
                        Endpoint_ClearSETUP();
-                       
+
                        /* Write 8-bit status value */
-                       Endpoint_Write_Byte(DFU_Status);
-                       
+                       Endpoint_Write_8(DFU_Status);
+
                        /* Write 24-bit poll timeout value */
-                       Endpoint_Write_Byte(0);
-                       Endpoint_Write_Word_LE(0);
-                       
+                       Endpoint_Write_8(0);
+                       Endpoint_Write_16_LE(0);
+
                        /* Write 8-bit state value */
-                       Endpoint_Write_Byte(DFU_State);
+                       Endpoint_Write_8(DFU_State);
 
                        /* Write 8-bit state string ID number */
-                       Endpoint_Write_Byte(0);
+                       Endpoint_Write_8(0);
 
                        Endpoint_ClearIN();
-                       
+
                        Endpoint_ClearStatusStage();
-                       break;          
-               case REQ_DFU_CLRSTATUS:
+                       break;
+               case DFU_REQ_CLRSTATUS:
                        Endpoint_ClearSETUP();
-                       
+
                        /* Reset the status value variable to the default OK status */
                        DFU_Status = OK;
 
                        Endpoint_ClearStatusStage();
                        break;
-               case REQ_DFU_GETSTATE:
+               case DFU_REQ_GETSTATE:
                        Endpoint_ClearSETUP();
-                       
+
                        /* Write the current device state to the endpoint */
-                       Endpoint_Write_Byte(DFU_State);
-               
+                       Endpoint_Write_8(DFU_State);
+
                        Endpoint_ClearIN();
-                       
+
                        Endpoint_ClearStatusStage();
                        break;
-               case REQ_DFU_ABORT:
+               case DFU_REQ_ABORT:
                        Endpoint_ClearSETUP();
-                       
+
                        /* Reset the current state variable to the default idle state */
                        DFU_State = dfuIDLE;
 
@@ -472,14 +513,14 @@ static void DiscardFillerBytes(uint8_t NumberOfBytes)
 
                        /* Wait until next data packet received */
                        while (!(Endpoint_IsOUTReceived()))
-                       {                               
+                       {
                                if (USB_DeviceState == DEVICE_STATE_Unattached)
                                  return;
                        }
                }
                else
                {
-                       Endpoint_Discard_Byte();
+                       Endpoint_Discard_8();
                }
        }
 }
@@ -501,10 +542,10 @@ static void ProcessBootloaderCommand(void)
                        /* 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;
                }
@@ -544,7 +585,7 @@ static void LoadStartEndAddresses(void)
                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;
@@ -560,7 +601,7 @@ static void ProcessMemProgCommand(void)
        {
                /* 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))
                {
@@ -569,12 +610,12 @@ static void ProcessMemProgCommand(void)
                                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;
        }
@@ -611,7 +652,7 @@ static void ProcessMemReadCommand(void)
                                /* 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;
@@ -680,7 +721,7 @@ static void ProcessWriteCommand(void)
 
                /* 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;
        }
@@ -701,3 +742,4 @@ static void ProcessReadCommand(void)
        else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01))                    // Read signature byte
          ResponseByte = SignatureInfo[DataIndexToRead - 0x30];
 }
+