source: arduino-1-6-7/trunk/fuentes/arduino-ide-amd64/hardware/arduino/avr/firmwares/atmegaxxu2/arduino-usbdfu/Arduino-usbdfu.c @ 4837

Last change on this file since 4837 was 4837, checked in by daduve, 3 years ago

Adding new version

File size: 23.4 KB
Line 
1/*
2             LUFA Library
3     Copyright (C) Dean Camera, 2010.
4             
5  dean [at] fourwalledcubicle [dot] com
6      www.fourwalledcubicle.com
7*/
8
9/*
10  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12  Permission to use, copy, modify, distribute, and sell this
13  software and its documentation for any purpose is hereby granted
14  without fee, provided that the above copyright notice appear in
15  all copies and that both that the copyright notice and this
16  permission notice and warranty disclaimer appear in supporting
17  documentation, and that the name of the author not be used in
18  advertising or publicity pertaining to distribution of the
19  software without specific, written prior permission.
20
21  The author disclaim all warranties with regard to this
22  software, including all implied warranties of merchantability
23  and fitness.  In no event shall the author be liable for any
24  special, indirect or consequential damages or any damages
25  whatsoever resulting from loss of use, data or profits, whether
26  in an action of contract, negligence or other tortious action,
27  arising out of or in connection with the use or performance of
28  this software.
29*/
30
31/** \file
32 *
33 *  Main source file for the DFU class bootloader. This file contains the complete bootloader logic.
34 */
35
36#define  INCLUDE_FROM_BOOTLOADER_C
37#include "Arduino-usbdfu.h"
38
39/** Flag to indicate if the bootloader should be running, or should exit and allow the application code to run
40 *  via a soft reset. When cleared, the bootloader will abort, the USB interface will shut down and the application
41 *  jumped to via an indirect jump to location 0x0000 (or other location specified by the host).
42 */
43bool RunBootloader = true;
44
45/** Flag to indicate if the bootloader is waiting to exit. When the host requests the bootloader to exit and
46 *  jump to the application address it specifies, it sends two sequential commands which must be properly
47 *  acknowledged. Upon reception of the first the RunBootloader flag is cleared and the WaitForExit flag is set,
48 *  causing the bootloader to wait for the final exit command before shutting down.
49 */
50bool WaitForExit = false;
51
52/** Current DFU state machine state, one of the values in the DFU_State_t enum. */
53uint8_t DFU_State = dfuIDLE;
54
55/** Status code of the last executed DFU command. This is set to one of the values in the DFU_Status_t enum after
56 *  each operation, and returned to the host when a Get Status DFU request is issued.
57 */
58uint8_t DFU_Status = OK;
59
60/** Data containing the DFU command sent from the host. */
61DFU_Command_t SentCommand;
62
63/** Response to the last issued Read Data DFU command. Unlike other DFU commands, the read command
64 *  requires a single byte response from the bootloader containing the read data when the next DFU_UPLOAD command
65 *  is issued by the host.
66 */
67uint8_t ResponseByte;
68
69/** Pointer to the start of the user application. By default this is 0x0000 (the reset vector), however the host
70 *  may specify an alternate address when issuing the application soft-start command.
71 */
72AppPtr_t AppStartPtr = (AppPtr_t)0x0000;
73
74/** 64-bit flash page number. This is concatenated with the current 16-bit address on USB AVRs containing more than
75 *  64KB of flash memory.
76 */
77uint8_t Flash64KBPage = 0;
78
79/** Memory start address, indicating the current address in the memory being addressed (either FLASH or EEPROM
80 *  depending on the issued command from the host).
81 */
82uint16_t StartAddr = 0x0000;
83
84/** Memory end address, indicating the end address to read to/write from in the memory being addressed (either FLASH
85 *  of EEPROM depending on the issued command from the host).
86 */
87uint16_t EndAddr = 0x0000;
88
89
90/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */
91volatile struct
92{
93        uint8_t TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */
94        uint8_t RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */
95        uint8_t PingPongLEDPulse; /**< Milliseconds remaining for enumeration Tx/Rx ping-pong LED pulse */
96} PulseMSRemaining;
97
98/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously
99 *  runs the bootloader processing routine until instructed to soft-exit, or hard-reset via the watchdog to start
100 *  the loaded application code.
101 */
102int main(void)
103{
104        /* Configure hardware required by the bootloader */
105        SetupHardware();
106       
107        /* Enable global interrupts so that the USB stack can function */
108        sei();
109
110        /* Run the USB management task while the bootloader is supposed to be running */
111        while (RunBootloader || WaitForExit)
112          USB_USBTask();
113       
114        /* Reset configured hardware back to their original states for the user application */
115        ResetHardware();
116       
117        /* Start the user application */
118        AppStartPtr();
119}
120
121/** Configures all hardware required for the bootloader. */
122void SetupHardware(void)
123{
124        /* Disable watchdog if enabled by bootloader/fuses */
125        MCUSR &= ~(1 << WDRF);
126        wdt_disable();
127
128        /* Disable clock division */
129//      clock_prescale_set(clock_div_1);
130       
131        /* Relocate the interrupt vector table to the bootloader section */
132        MCUCR = (1 << IVCE);
133        MCUCR = (1 << IVSEL);
134
135        LEDs_Init();
136
137        /* Initialize the USB subsystem */
138        USB_Init();
139}
140
141/** Resets all configured hardware required for the bootloader back to their original states. */
142void ResetHardware(void)
143{
144        /* Shut down the USB subsystem */
145        USB_ShutDown();
146       
147        /* Relocate the interrupt vector table back to the application section */
148        MCUCR = (1 << IVCE);
149        MCUCR = 0;
150}
151
152/** Event handler for the USB_UnhandledControlRequest event. This is used to catch standard and class specific
153 *  control requests that are not handled internally by the USB library (including the DFU commands, which are
154 *  all issued via the control endpoint), so that they can be handled appropriately for the application.
155 */
156void EVENT_USB_Device_UnhandledControlRequest(void)
157{
158        /* Get the size of the command and data from the wLength value */
159        SentCommand.DataSize = USB_ControlRequest.wLength;
160
161        /* Turn off TX LED(s) once the TX pulse period has elapsed */
162        if (PulseMSRemaining.TxLEDPulse && !(--PulseMSRemaining.TxLEDPulse))
163                LEDs_TurnOffLEDs(LEDMASK_TX);
164               
165        /* Turn off RX LED(s) once the RX pulse period has elapsed */
166        if (PulseMSRemaining.RxLEDPulse && !(--PulseMSRemaining.RxLEDPulse))
167                LEDs_TurnOffLEDs(LEDMASK_RX);
168
169        switch (USB_ControlRequest.bRequest)
170        {
171                case DFU_DNLOAD:
172                        LEDs_TurnOnLEDs(LEDMASK_RX);
173                        PulseMSRemaining.RxLEDPulse = TX_RX_LED_PULSE_MS;               
174               
175                        Endpoint_ClearSETUP();
176                       
177                        /* Check if bootloader is waiting to terminate */
178                        if (WaitForExit)
179                        {
180                                /* Bootloader is terminating - process last received command */
181                                ProcessBootloaderCommand();
182                               
183                                /* Turn off TX/RX status LEDs so that they're not left on when application starts */
184                                LEDs_TurnOffLEDs(LEDMASK_TX);
185                                LEDs_TurnOffLEDs(LEDMASK_RX);
186                               
187                                /* Indicate that the last command has now been processed - free to exit bootloader */
188                                WaitForExit = false;
189                        }
190                         
191                        /* If the request has a data stage, load it into the command struct */
192                        if (SentCommand.DataSize)
193                        {
194                                while (!(Endpoint_IsOUTReceived()))
195                                {                               
196                                        if (USB_DeviceState == DEVICE_STATE_Unattached)
197                                          return;
198                                }
199
200                                /* First byte of the data stage is the DNLOAD request's command */
201                                SentCommand.Command = Endpoint_Read_Byte();
202                                       
203                                /* One byte of the data stage is the command, so subtract it from the total data bytes */
204                                SentCommand.DataSize--;
205                               
206                                /* Load in the rest of the data stage as command parameters */
207                                for (uint8_t DataByte = 0; (DataByte < sizeof(SentCommand.Data)) &&
208                                     Endpoint_BytesInEndpoint(); DataByte++)
209                                {
210                                        SentCommand.Data[DataByte] = Endpoint_Read_Byte();
211                                        SentCommand.DataSize--;
212                                }
213                               
214                                /* Process the command */
215                                ProcessBootloaderCommand();
216                        }
217                       
218                        /* Check if currently downloading firmware */
219                        if (DFU_State == dfuDNLOAD_IDLE)
220                        {                                                                       
221                                if (!(SentCommand.DataSize))
222                                {
223                                        DFU_State = dfuIDLE;
224                                }
225                                else
226                                {
227                                        /* Throw away the filler bytes before the start of the firmware */
228                                        DiscardFillerBytes(DFU_FILLER_BYTES_SIZE);
229
230                                        /* Throw away the packet alignment filler bytes before the start of the firmware */
231                                        DiscardFillerBytes(StartAddr % FIXED_CONTROL_ENDPOINT_SIZE);
232                                       
233                                        /* Calculate the number of bytes remaining to be written */
234                                        uint16_t BytesRemaining = ((EndAddr - StartAddr) + 1);
235                                       
236                                        if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00))        // Write flash
237                                        {
238                                                /* Calculate the number of words to be written from the number of bytes to be written */
239                                                uint16_t WordsRemaining = (BytesRemaining >> 1);
240                                       
241                                                union
242                                                {
243                                                        uint16_t Words[2];
244                                                        uint32_t Long;
245                                                } CurrFlashAddress                 = {.Words = {StartAddr, Flash64KBPage}};
246                                               
247                                                uint32_t CurrFlashPageStartAddress = CurrFlashAddress.Long;
248                                                uint8_t  WordsInFlashPage          = 0;
249
250                                                while (WordsRemaining--)
251                                                {
252                                                        /* Check if endpoint is empty - if so clear it and wait until ready for next packet */
253                                                        if (!(Endpoint_BytesInEndpoint()))
254                                                        {
255                                                                Endpoint_ClearOUT();
256
257                                                                while (!(Endpoint_IsOUTReceived()))
258                                                                {                               
259                                                                        if (USB_DeviceState == DEVICE_STATE_Unattached)
260                                                                          return;
261                                                                }
262                                                        }
263
264                                                        /* Write the next word into the current flash page */
265                                                        boot_page_fill(CurrFlashAddress.Long, Endpoint_Read_Word_LE());
266
267                                                        /* Adjust counters */
268                                                        WordsInFlashPage      += 1;
269                                                        CurrFlashAddress.Long += 2;
270
271                                                        /* See if an entire page has been written to the flash page buffer */
272                                                        if ((WordsInFlashPage == (SPM_PAGESIZE >> 1)) || !(WordsRemaining))
273                                                        {
274                                                                /* Commit the flash page to memory */
275                                                                boot_page_write(CurrFlashPageStartAddress);
276                                                                boot_spm_busy_wait();
277                                                               
278                                                                /* Check if programming incomplete */
279                                                                if (WordsRemaining)
280                                                                {
281                                                                        CurrFlashPageStartAddress = CurrFlashAddress.Long;
282                                                                        WordsInFlashPage          = 0;
283
284                                                                        /* Erase next page's temp buffer */
285                                                                        boot_page_erase(CurrFlashAddress.Long);
286                                                                        boot_spm_busy_wait();
287                                                                }
288                                                        }
289                                                }
290                                       
291                                                /* Once programming complete, start address equals the end address */
292                                                StartAddr = EndAddr;
293                                       
294                                                /* Re-enable the RWW section of flash */
295                                                boot_rww_enable();
296                                        }
297                                        else                                                   // Write EEPROM
298                                        {
299                                                while (BytesRemaining--)
300                                                {
301                                                        /* Check if endpoint is empty - if so clear it and wait until ready for next packet */
302                                                        if (!(Endpoint_BytesInEndpoint()))
303                                                        {
304                                                                Endpoint_ClearOUT();
305
306                                                                while (!(Endpoint_IsOUTReceived()))
307                                                                {                               
308                                                                        if (USB_DeviceState == DEVICE_STATE_Unattached)
309                                                                          return;
310                                                                }
311                                                        }
312
313                                                        /* Read the byte from the USB interface and write to to the EEPROM */
314                                                        eeprom_write_byte((uint8_t*)StartAddr, Endpoint_Read_Byte());
315                                                       
316                                                        /* Adjust counters */
317                                                        StartAddr++;
318                                                }
319                                        }
320                                       
321                                        /* Throw away the currently unused DFU file suffix */
322                                        DiscardFillerBytes(DFU_FILE_SUFFIX_SIZE);
323                                }
324                        }
325
326                        Endpoint_ClearOUT();
327
328                        Endpoint_ClearStatusStage();
329
330                        break;
331                case DFU_UPLOAD:
332                        Endpoint_ClearSETUP();
333                       
334                        LEDs_TurnOnLEDs(LEDMASK_TX);
335                        PulseMSRemaining.TxLEDPulse = TX_RX_LED_PULSE_MS;
336
337                        while (!(Endpoint_IsINReady()))
338                        {                               
339                                if (USB_DeviceState == DEVICE_STATE_Unattached)
340                                  return;
341                        }
342                                                       
343                        if (DFU_State != dfuUPLOAD_IDLE)
344                        {
345                                if ((DFU_State == dfuERROR) && IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01))       // Blank Check
346                                {
347                                        /* Blank checking is performed in the DFU_DNLOAD request - if we get here we've told the host
348                                           that the memory isn't blank, and the host is requesting the first non-blank address */
349                                        Endpoint_Write_Word_LE(StartAddr);
350                                }
351                                else
352                                {
353                                        /* Idle state upload - send response to last issued command */
354                                        Endpoint_Write_Byte(ResponseByte);
355                                }
356                        }
357                        else
358                        {
359                                /* Determine the number of bytes remaining in the current block */
360                                uint16_t BytesRemaining = ((EndAddr - StartAddr) + 1);
361
362                                if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00))            // Read FLASH
363                                {
364                                        /* Calculate the number of words to be written from the number of bytes to be written */
365                                        uint16_t WordsRemaining = (BytesRemaining >> 1);
366
367                                        union
368                                        {
369                                                uint16_t Words[2];
370                                                uint32_t Long;
371                                        } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}};
372
373                                        while (WordsRemaining--)
374                                        {
375                                                /* Check if endpoint is full - if so clear it and wait until ready for next packet */
376                                                if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE)
377                                                {
378                                                        Endpoint_ClearIN();
379
380                                                        while (!(Endpoint_IsINReady()))
381                                                        {                               
382                                                                if (USB_DeviceState == DEVICE_STATE_Unattached)
383                                                                  return;
384                                                        }
385                                                }
386
387                                                /* Read the flash word and send it via USB to the host */
388                                                #if (FLASHEND > 0xFFFF)
389                                                        Endpoint_Write_Word_LE(pgm_read_word_far(CurrFlashAddress.Long));
390                                                #else
391                                                        Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long));                                                   
392                                                #endif
393
394                                                /* Adjust counters */
395                                                CurrFlashAddress.Long += 2;
396                                        }
397                                       
398                                        /* Once reading is complete, start address equals the end address */
399                                        StartAddr = EndAddr;
400                                }
401                                else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x02))       // Read EEPROM
402                                {
403                                        while (BytesRemaining--)
404                                        {
405                                                /* Check if endpoint is full - if so clear it and wait until ready for next packet */
406                                                if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE)
407                                                {
408                                                        Endpoint_ClearIN();
409                                                       
410                                                        while (!(Endpoint_IsINReady()))
411                                                        {                               
412                                                                if (USB_DeviceState == DEVICE_STATE_Unattached)
413                                                                  return;
414                                                        }
415                                                }
416
417                                                /* Read the EEPROM byte and send it via USB to the host */
418                                                Endpoint_Write_Byte(eeprom_read_byte((uint8_t*)StartAddr));
419
420                                                /* Adjust counters */
421                                                StartAddr++;
422                                        }
423                                }
424
425                                /* Return to idle state */
426                                DFU_State = dfuIDLE;
427                        }
428
429                        Endpoint_ClearIN();
430
431                        Endpoint_ClearStatusStage();
432                        break;
433                case DFU_GETSTATUS:
434                        Endpoint_ClearSETUP();
435                       
436                        /* Write 8-bit status value */
437                        Endpoint_Write_Byte(DFU_Status);
438                       
439                        /* Write 24-bit poll timeout value */
440                        Endpoint_Write_Byte(0);
441                        Endpoint_Write_Word_LE(0);
442                       
443                        /* Write 8-bit state value */
444                        Endpoint_Write_Byte(DFU_State);
445
446                        /* Write 8-bit state string ID number */
447                        Endpoint_Write_Byte(0);
448
449                        Endpoint_ClearIN();
450                       
451                        Endpoint_ClearStatusStage();
452                        break;         
453                case DFU_CLRSTATUS:
454                        Endpoint_ClearSETUP();
455                       
456                        /* Reset the status value variable to the default OK status */
457                        DFU_Status = OK;
458
459                        Endpoint_ClearStatusStage();
460                        break;
461                case DFU_GETSTATE:
462                        Endpoint_ClearSETUP();
463                       
464                        /* Write the current device state to the endpoint */
465                        Endpoint_Write_Byte(DFU_State);
466               
467                        Endpoint_ClearIN();
468                       
469                        Endpoint_ClearStatusStage();
470                        break;
471                case DFU_ABORT:
472                        Endpoint_ClearSETUP();
473                       
474                        /* Turn off TX/RX status LEDs so that they're not left on when application starts */
475                        LEDs_TurnOffLEDs(LEDMASK_TX);
476                        LEDs_TurnOffLEDs(LEDMASK_RX);
477                       
478                        /* Reset the current state variable to the default idle state */
479                        DFU_State = dfuIDLE;
480
481                        Endpoint_ClearStatusStage();
482                        break;
483        }
484}
485
486/** Routine to discard the specified number of bytes from the control endpoint stream. This is used to
487 *  discard unused bytes in the stream from the host, including the memory program block suffix.
488 *
489 *  \param[in] NumberOfBytes  Number of bytes to discard from the host from the control endpoint
490 */
491static void DiscardFillerBytes(uint8_t NumberOfBytes)
492{
493        while (NumberOfBytes--)
494        {
495                if (!(Endpoint_BytesInEndpoint()))
496                {
497                        Endpoint_ClearOUT();
498
499                        /* Wait until next data packet received */
500                        while (!(Endpoint_IsOUTReceived()))
501                        {                               
502                                if (USB_DeviceState == DEVICE_STATE_Unattached)
503                                  return;
504                        }
505                }
506                else
507                {
508                        Endpoint_Discard_Byte();
509                }
510        }
511}
512
513/** Routine to process an issued command from the host, via a DFU_DNLOAD request wrapper. This routine ensures
514 *  that the command is allowed based on the current secure mode flag value, and passes the command off to the
515 *  appropriate handler function.
516 */
517static void ProcessBootloaderCommand(void)
518{
519        /* Check if device is in secure mode */
520//      if (IsSecure)
521//      {
522//              /* Don't process command unless it is a READ or chip erase command */
523//              if (!(((SentCommand.Command == COMMAND_WRITE)             &&
524//                      IS_TWOBYTE_COMMAND(SentCommand.Data, 0x00, 0xFF)) ||
525//                         (SentCommand.Command == COMMAND_READ)))
526//              {
527//                      /* Set the state and status variables to indicate the error */
528//                      DFU_State  = dfuERROR;
529//                      DFU_Status = errWRITE;
530//                     
531//                      /* Stall command */
532//                      Endpoint_StallTransaction();
533//                     
534//                      /* Don't process the command */
535//                      return;
536//              }
537//      }
538
539        /* Dispatch the required command processing routine based on the command type */
540        switch (SentCommand.Command)
541        {
542                case COMMAND_PROG_START:
543                        ProcessMemProgCommand();
544                        break;
545                case COMMAND_DISP_DATA:
546                        ProcessMemReadCommand();
547                        break;
548                case COMMAND_WRITE:
549                        ProcessWriteCommand();
550                        break;
551                case COMMAND_READ:
552                        ProcessReadCommand();
553                        break;
554                case COMMAND_CHANGE_BASE_ADDR:
555                        if (IS_TWOBYTE_COMMAND(SentCommand.Data, 0x03, 0x00))              // Set 64KB flash page command
556                          Flash64KBPage = SentCommand.Data[2];
557                        break;
558        }
559}
560
561/** Routine to concatenate the given pair of 16-bit memory start and end addresses from the host, and store them
562 *  in the StartAddr and EndAddr global variables.
563 */
564static void LoadStartEndAddresses(void)
565{
566        union
567        {
568                uint8_t  Bytes[2];
569                uint16_t Word;
570        } Address[2] = {{.Bytes = {SentCommand.Data[2], SentCommand.Data[1]}},
571                        {.Bytes = {SentCommand.Data[4], SentCommand.Data[3]}}};
572               
573        /* Load in the start and ending read addresses from the sent data packet */
574        StartAddr = Address[0].Word;
575        EndAddr   = Address[1].Word;
576}
577
578/** Handler for a Memory Program command issued by the host. This routine handles the preparations needed
579 *  to write subsequent data from the host into the specified memory.
580 */
581static void ProcessMemProgCommand(void)
582{
583        if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00) ||                          // Write FLASH command
584            IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01))                            // Write EEPROM command
585        {
586                /* Load in the start and ending read addresses */
587                LoadStartEndAddresses();
588               
589                /* If FLASH is being written to, we need to pre-erase the first page to write to */
590                if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00))
591                {
592                        union
593                        {
594                                uint16_t Words[2];
595                                uint32_t Long;
596                        } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}};
597                       
598                        /* Erase the current page's temp buffer */
599                        boot_page_erase(CurrFlashAddress.Long);
600                        boot_spm_busy_wait();
601                }
602               
603                /* Set the state so that the next DNLOAD requests reads in the firmware */
604                DFU_State = dfuDNLOAD_IDLE;
605        }
606}
607
608/** Handler for a Memory Read command issued by the host. This routine handles the preparations needed
609 *  to read subsequent data from the specified memory out to the host, as well as implementing the memory
610 *  blank check command.
611 */
612static void ProcessMemReadCommand(void)
613{
614        if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00) ||                          // Read FLASH command
615        IS_ONEBYTE_COMMAND(SentCommand.Data, 0x02))                            // Read EEPROM command
616        {
617                /* Load in the start and ending read addresses */
618                LoadStartEndAddresses();
619
620                /* Set the state so that the next UPLOAD requests read out the firmware */
621                DFU_State = dfuUPLOAD_IDLE;
622        }
623        else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01))                       // Blank check FLASH command
624        {
625                uint32_t CurrFlashAddress = 0;
626
627                while (CurrFlashAddress < BOOT_START_ADDR)
628                {
629                        /* Check if the current byte is not blank */
630                        #if (FLASHEND > 0xFFFF)
631                        if (pgm_read_byte_far(CurrFlashAddress) != 0xFF)
632                        #else
633                        if (pgm_read_byte(CurrFlashAddress) != 0xFF)
634                        #endif
635                        {
636                                /* Save the location of the first non-blank byte for response back to the host */
637                                Flash64KBPage = (CurrFlashAddress >> 16);
638                                StartAddr     = CurrFlashAddress;
639                       
640                                /* Set state and status variables to the appropriate error values */
641                                DFU_State  = dfuERROR;
642                                DFU_Status = errCHECK_ERASED;
643
644                                break;
645                        }
646
647                        CurrFlashAddress++;
648                }
649        }
650}
651
652/** Handler for a Data Write command issued by the host. This routine handles non-programming commands such as
653 *  bootloader exit (both via software jumps and hardware watchdog resets) and flash memory erasure.
654 */
655static void ProcessWriteCommand(void)
656{
657        if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x03))                            // Start application
658        {
659                /* Indicate that the bootloader is terminating */
660                WaitForExit = true;
661
662                /* Check if data supplied for the Start Program command - no data executes the program */
663                if (SentCommand.DataSize)
664                {
665                        if (SentCommand.Data[1] == 0x01)                                   // Start via jump
666                        {
667                                union
668                                {
669                                        uint8_t  Bytes[2];
670                                        AppPtr_t FuncPtr;
671                                } Address = {.Bytes = {SentCommand.Data[4], SentCommand.Data[3]}};
672
673                                /* Load in the jump address into the application start address pointer */
674                                AppStartPtr = Address.FuncPtr;
675                        }
676                }
677                else
678                {
679                        if (SentCommand.Data[1] == 0x00)                                   // Start via watchdog
680                        {
681                                /* Start the watchdog to reset the AVR once the communications are finalized */
682                                wdt_enable(WDTO_250MS);
683                        }
684                        else                                                               // Start via jump
685                        {
686                                /* Set the flag to terminate the bootloader at next opportunity */
687                                RunBootloader = false;
688                        }
689                }
690        }
691        else if (IS_TWOBYTE_COMMAND(SentCommand.Data, 0x00, 0xFF))                 // Erase flash
692        {
693                uint32_t CurrFlashAddress = 0;
694
695                /* Clear the application section of flash */
696                while (CurrFlashAddress < BOOT_START_ADDR)
697                {
698                        boot_page_erase(CurrFlashAddress);
699                        boot_spm_busy_wait();
700                        boot_page_write(CurrFlashAddress);
701                        boot_spm_busy_wait();
702
703                        CurrFlashAddress += SPM_PAGESIZE;
704                }
705
706                /* Re-enable the RWW section of flash as writing to the flash locks it out */
707                boot_rww_enable();
708                                       
709                /* Memory has been erased, reset the security bit so that programming/reading is allowed */
710//              IsSecure = false;
711        }
712}
713
714/** Handler for a Data Read command issued by the host. This routine handles bootloader information retrieval
715 *  commands such as device signature and bootloader version retrieval.
716 */
717static void ProcessReadCommand(void)
718{
719        const uint8_t BootloaderInfo[3] = {BOOTLOADER_VERSION, BOOTLOADER_ID_BYTE1, BOOTLOADER_ID_BYTE2};
720        const uint8_t SignatureInfo[3]  = {AVR_SIGNATURE_1,    AVR_SIGNATURE_2,     AVR_SIGNATURE_3};
721
722        uint8_t DataIndexToRead = SentCommand.Data[1];
723
724        if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00))                         // Read bootloader info
725          ResponseByte = BootloaderInfo[DataIndexToRead];
726        else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01))                    // Read signature byte
727          ResponseByte = SignatureInfo[DataIndexToRead - 0x30];
728}
Note: See TracBrowser for help on using the repository browser.