sanguino/firmwares/arduino-usbdfu/Arduino-usbdfu.c

changeset 2
b373b0288715
equal deleted inserted replaced
1:b584642d4f58 2:b373b0288715
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 */
43 bool 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 */
50 bool WaitForExit = false;
51
52 /** Current DFU state machine state, one of the values in the DFU_State_t enum. */
53 uint8_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 */
58 uint8_t DFU_Status = OK;
59
60 /** Data containing the DFU command sent from the host. */
61 DFU_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 */
67 uint8_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 */
72 AppPtr_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 */
77 uint8_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 */
82 uint16_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 */
87 uint16_t EndAddr = 0x0000;
88
89
90 /** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */
91 volatile 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 */
102 int 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. */
122 void 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. */
142 void 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 */
156 void 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 */
491 static 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 */
517 static 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 */
564 static 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 */
581 static 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 */
612 static 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 */
655 static 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 */
717 static 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 }

mercurial