source: arduino-1-6-7/trunk/fuentes/arduino-ide-amd64/hardware/arduino/avr/bootloaders/caterina/Caterina.c @ 4837

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

Adding new version

File size: 20.6 KB
Line 
1/*
2             LUFA Library
3     Copyright (C) Dean Camera, 2011.
4
5  dean [at] fourwalledcubicle [dot] com
6           www.lufa-lib.org
7*/
8
9/*
10  Copyright 2011  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 CDC class bootloader. This file contains the complete bootloader logic.
34 */
35
36#define  INCLUDE_FROM_CATERINA_C
37#include "Caterina.h"
38
39/** Contains the current baud rate and other settings of the first virtual serial port. This must be retained as some
40 *  operating systems will not open the port unless the settings can be set successfully.
41 */
42static CDC_LineEncoding_t LineEncoding = { .BaudRateBPS = 0,
43                                           .CharFormat  = CDC_LINEENCODING_OneStopBit,
44                                           .ParityType  = CDC_PARITY_None,
45                                           .DataBits    = 8                            };
46
47/** Current address counter. This stores the current address of the FLASH or EEPROM as set by the host,
48 *  and is used when reading or writing to the AVRs memory (either FLASH or EEPROM depending on the issued
49 *  command.)
50 */
51static uint32_t CurrAddress;
52
53/** Flag to indicate if the bootloader should be running, or should exit and allow the application code to run
54 *  via a watchdog reset. When cleared the bootloader will exit, starting the watchdog and entering an infinite
55 *  loop until the AVR restarts and the application runs.
56 */
57static bool RunBootloader = true;
58
59/* Pulse generation counters to keep track of the time remaining for each pulse type */
60#define TX_RX_LED_PULSE_PERIOD 100
61uint16_t TxLEDPulse = 0; // time remaining for Tx LED pulse
62uint16_t RxLEDPulse = 0; // time remaining for Rx LED pulse
63
64/* Bootloader timeout timer */
65#define TIMEOUT_PERIOD  8000
66uint16_t Timeout = 0;
67
68uint16_t bootKey = 0x7777;
69volatile uint16_t *const bootKeyPtr = (volatile uint16_t *)0x0800;
70
71void StartSketch(void)
72{
73        cli();
74       
75        /* Undo TIMER1 setup and clear the count before running the sketch */
76        TIMSK1 = 0;
77        TCCR1B = 0;
78        TCNT1H = 0;             // 16-bit write to TCNT1 requires high byte be written first
79        TCNT1L = 0;
80       
81        /* Relocate the interrupt vector table to the application section */
82        MCUCR = (1 << IVCE);
83        MCUCR = 0;
84
85        L_LED_OFF();
86        TX_LED_OFF();
87        RX_LED_OFF();
88
89        /* jump to beginning of application space */
90        __asm__ volatile("jmp 0x0000");
91}
92
93/*      Breathing animation on L LED indicates bootloader is running */
94uint16_t LLEDPulse;
95void LEDPulse(void)
96{
97        LLEDPulse++;
98        uint8_t p = LLEDPulse >> 8;
99        if (p > 127)
100                p = 254-p;
101        p += p;
102        if (((uint8_t)LLEDPulse) > p)
103                L_LED_OFF();
104        else
105                L_LED_ON();
106}
107
108/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously
109 *  runs the bootloader processing routine until it times out or is instructed to exit.
110 */
111int main(void)
112{
113        /* Save the value of the boot key memory before it is overwritten */
114        uint16_t bootKeyPtrVal = *bootKeyPtr;
115        *bootKeyPtr = 0;
116
117        /* Check the reason for the reset so we can act accordingly */
118        uint8_t  mcusr_state = MCUSR;           // store the initial state of the Status register
119        MCUSR = 0;                                                      // clear all reset flags       
120
121        /* Watchdog may be configured with a 15 ms period so must disable it before going any further */
122        wdt_disable();
123       
124        if (mcusr_state & (1<<EXTRF)) {
125                // External reset -  we should continue to self-programming mode.
126        } else if ((mcusr_state & (1<<PORF)) && (pgm_read_word(0) != 0xFFFF)) {         
127                // After a power-on reset skip the bootloader and jump straight to sketch
128                // if one exists.       
129                StartSketch();
130        } else if ((mcusr_state & (1<<WDRF)) && (bootKeyPtrVal != bootKey) && (pgm_read_word(0) != 0xFFFF)) {   
131                // If it looks like an "accidental" watchdog reset then start the sketch.
132                StartSketch();
133        }
134       
135        /* Setup hardware required for the bootloader */
136        SetupHardware();
137
138        /* Enable global interrupts so that the USB stack can function */
139        sei();
140       
141        Timeout = 0;
142       
143        while (RunBootloader)
144        {
145                CDC_Task();
146                USB_USBTask();
147                /* Time out and start the sketch if one is present */
148                if (Timeout > TIMEOUT_PERIOD)
149                        RunBootloader = false;
150
151                LEDPulse();
152        }
153
154        /* Disconnect from the host - USB interface will be reset later along with the AVR */
155        USB_Detach();
156
157        /* Jump to beginning of application space to run the sketch - do not reset */   
158        StartSketch();
159}
160
161/** Configures all hardware required for the bootloader. */
162void SetupHardware(void)
163{
164        /* Disable watchdog if enabled by bootloader/fuses */
165        MCUSR &= ~(1 << WDRF);
166        wdt_disable();
167
168        /* Disable clock division */
169        clock_prescale_set(clock_div_1);
170
171        /* Relocate the interrupt vector table to the bootloader section */
172        MCUCR = (1 << IVCE);
173        MCUCR = (1 << IVSEL);
174       
175        LED_SETUP();
176        CPU_PRESCALE(0); 
177        L_LED_OFF();
178        TX_LED_OFF();
179        RX_LED_OFF();
180       
181        /* Initialize TIMER1 to handle bootloader timeout and LED tasks. 
182         * With 16 MHz clock and 1/64 prescaler, timer 1 is clocked at 250 kHz
183         * Our chosen compare match generates an interrupt every 1 ms.
184         * This interrupt is disabled selectively when doing memory reading, erasing,
185         * or writing since SPM has tight timing requirements.
186         */ 
187        OCR1AH = 0;
188        OCR1AL = 250;
189        TIMSK1 = (1 << OCIE1A);                                 // enable timer 1 output compare A match interrupt
190        TCCR1B = ((1 << CS11) | (1 << CS10));   // 1/64 prescaler on timer 1 input
191
192        /* Initialize USB Subsystem */
193        USB_Init();
194}
195
196//uint16_t ctr = 0;
197ISR(TIMER1_COMPA_vect, ISR_BLOCK)
198{
199        /* Reset counter */
200        TCNT1H = 0;
201        TCNT1L = 0;
202
203        /* Check whether the TX or RX LED one-shot period has elapsed.  if so, turn off the LED */
204        if (TxLEDPulse && !(--TxLEDPulse))
205                TX_LED_OFF();
206        if (RxLEDPulse && !(--RxLEDPulse))
207                RX_LED_OFF();
208       
209        if (pgm_read_word(0) != 0xFFFF)
210                Timeout++;
211}
212
213/** Event handler for the USB_ConfigurationChanged event. This configures the device's endpoints ready
214 *  to relay data to and from the attached USB host.
215 */
216void EVENT_USB_Device_ConfigurationChanged(void)
217{
218        /* Setup CDC Notification, Rx and Tx Endpoints */
219        Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT,
220                                   ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE,
221                                   ENDPOINT_BANK_SINGLE);
222
223        Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK,
224                                   ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE,
225                                   ENDPOINT_BANK_SINGLE);
226
227        Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK,
228                                   ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE,
229                                   ENDPOINT_BANK_SINGLE);
230}
231
232/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
233 *  the device from the USB host before passing along unhandled control requests to the library for processing
234 *  internally.
235 */
236void EVENT_USB_Device_ControlRequest(void)
237{
238        /* Ignore any requests that aren't directed to the CDC interface */
239        if ((USB_ControlRequest.bmRequestType & (CONTROL_REQTYPE_TYPE | CONTROL_REQTYPE_RECIPIENT)) !=
240            (REQTYPE_CLASS | REQREC_INTERFACE))
241        {
242                return;
243        }
244
245        /* Process CDC specific control requests */
246        switch (USB_ControlRequest.bRequest)
247        {
248                case CDC_REQ_GetLineEncoding:
249                        if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
250                        {
251                                Endpoint_ClearSETUP();
252
253                                /* Write the line coding data to the control endpoint */
254                                Endpoint_Write_Control_Stream_LE(&LineEncoding, sizeof(CDC_LineEncoding_t));
255                                Endpoint_ClearOUT();
256                        }
257
258                        break;
259                case CDC_REQ_SetLineEncoding:
260                        if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
261                        {
262                                Endpoint_ClearSETUP();
263
264                                /* Read the line coding data in from the host into the global struct */
265                                Endpoint_Read_Control_Stream_LE(&LineEncoding, sizeof(CDC_LineEncoding_t));
266                                Endpoint_ClearIN();
267                        }
268
269                        break;
270        }
271}
272
273#if !defined(NO_BLOCK_SUPPORT)
274/** Reads or writes a block of EEPROM or FLASH memory to or from the appropriate CDC data endpoint, depending
275 *  on the AVR910 protocol command issued.
276 *
277 *  \param[in] Command  Single character AVR910 protocol command indicating what memory operation to perform
278 */
279static void ReadWriteMemoryBlock(const uint8_t Command)
280{
281        uint16_t BlockSize;
282        char     MemoryType;
283
284        bool     HighByte = false;
285        uint8_t  LowByte  = 0;
286
287        BlockSize  = (FetchNextCommandByte() << 8);
288        BlockSize |=  FetchNextCommandByte();
289
290        MemoryType =  FetchNextCommandByte();
291
292        if ((MemoryType != 'E') && (MemoryType != 'F'))
293        {
294                /* Send error byte back to the host */
295                WriteNextResponseByte('?');
296
297                return;
298        }
299
300        /* Disable timer 1 interrupt - can't afford to process nonessential interrupts
301         * while doing SPM tasks */
302        TIMSK1 = 0;
303
304        /* Check if command is to read memory */
305        if (Command == 'g')
306        {               
307                /* Re-enable RWW section */
308                boot_rww_enable();
309
310                while (BlockSize--)
311                {
312                        if (MemoryType == 'F')
313                        {
314                                /* Read the next FLASH byte from the current FLASH page */
315                                #if (FLASHEND > 0xFFFF)
316                                WriteNextResponseByte(pgm_read_byte_far(CurrAddress | HighByte));
317                                #else
318                                WriteNextResponseByte(pgm_read_byte(CurrAddress | HighByte));
319                                #endif
320
321                                /* If both bytes in current word have been read, increment the address counter */
322                                if (HighByte)
323                                  CurrAddress += 2;
324
325                                HighByte = !HighByte;
326                        }
327                        else
328                        {
329                                /* Read the next EEPROM byte into the endpoint */
330                                WriteNextResponseByte(eeprom_read_byte((uint8_t*)(intptr_t)(CurrAddress >> 1)));
331
332                                /* Increment the address counter after use */
333                                CurrAddress += 2;
334                        }
335                }
336        }
337        else
338        {
339                uint32_t PageStartAddress = CurrAddress;
340
341                if (MemoryType == 'F')
342                {
343                        boot_page_erase(PageStartAddress);
344                        boot_spm_busy_wait();
345                }
346
347                while (BlockSize--)
348                {
349                        if (MemoryType == 'F')
350                        {
351                                /* If both bytes in current word have been written, increment the address counter */
352                                if (HighByte)
353                                {
354                                        /* Write the next FLASH word to the current FLASH page */
355                                        boot_page_fill(CurrAddress, ((FetchNextCommandByte() << 8) | LowByte));
356
357                                        /* Increment the address counter after use */
358                                        CurrAddress += 2;
359                                }
360                                else
361                                {
362                                        LowByte = FetchNextCommandByte();
363                                }
364                               
365                                HighByte = !HighByte;
366                        }
367                        else
368                        {
369                                /* Write the next EEPROM byte from the endpoint */
370                                eeprom_write_byte((uint8_t*)((intptr_t)(CurrAddress >> 1)), FetchNextCommandByte());
371
372                                /* Increment the address counter after use */
373                                CurrAddress += 2;
374                        }
375                }
376
377                /* If in FLASH programming mode, commit the page after writing */
378                if (MemoryType == 'F')
379                {
380                        /* Commit the flash page to memory */
381                        boot_page_write(PageStartAddress);
382
383                        /* Wait until write operation has completed */
384                        boot_spm_busy_wait();
385                }
386
387                /* Send response byte back to the host */
388                WriteNextResponseByte('\r');
389        }
390
391        /* Re-enable timer 1 interrupt disabled earlier in this routine */     
392        TIMSK1 = (1 << OCIE1A);
393}
394#endif
395
396/** Retrieves the next byte from the host in the CDC data OUT endpoint, and clears the endpoint bank if needed
397 *  to allow reception of the next data packet from the host.
398 *
399 *  \return Next received byte from the host in the CDC data OUT endpoint
400 */
401static uint8_t FetchNextCommandByte(void)
402{
403        /* Select the OUT endpoint so that the next data byte can be read */
404        Endpoint_SelectEndpoint(CDC_RX_EPNUM);
405
406        /* If OUT endpoint empty, clear it and wait for the next packet from the host */
407        while (!(Endpoint_IsReadWriteAllowed()))
408        {
409                Endpoint_ClearOUT();
410
411                while (!(Endpoint_IsOUTReceived()))
412                {
413                        if (USB_DeviceState == DEVICE_STATE_Unattached)
414                          return 0;
415                }
416        }
417
418        /* Fetch the next byte from the OUT endpoint */
419        return Endpoint_Read_8();
420}
421
422/** Writes the next response byte to the CDC data IN endpoint, and sends the endpoint back if needed to free up the
423 *  bank when full ready for the next byte in the packet to the host.
424 *
425 *  \param[in] Response  Next response byte to send to the host
426 */
427static void WriteNextResponseByte(const uint8_t Response)
428{
429        /* Select the IN endpoint so that the next data byte can be written */
430        Endpoint_SelectEndpoint(CDC_TX_EPNUM);
431
432        /* If IN endpoint full, clear it and wait until ready for the next packet to the host */
433        if (!(Endpoint_IsReadWriteAllowed()))
434        {
435                Endpoint_ClearIN();
436
437                while (!(Endpoint_IsINReady()))
438                {
439                        if (USB_DeviceState == DEVICE_STATE_Unattached)
440                          return;
441                }
442        }
443
444        /* Write the next byte to the IN endpoint */
445        Endpoint_Write_8(Response);
446       
447        TX_LED_ON();
448        TxLEDPulse = TX_RX_LED_PULSE_PERIOD;
449}
450
451#define STK_OK              0x10
452#define STK_INSYNC          0x14  // ' '
453#define CRC_EOP             0x20  // 'SPACE'
454#define STK_GET_SYNC        0x30  // '0'
455
456#define STK_GET_PARAMETER   0x41  // 'A'
457#define STK_SET_DEVICE      0x42  // 'B'
458#define STK_SET_DEVICE_EXT  0x45  // 'E'
459#define STK_LOAD_ADDRESS    0x55  // 'U'
460#define STK_UNIVERSAL       0x56  // 'V'
461#define STK_PROG_PAGE       0x64  // 'd'
462#define STK_READ_PAGE       0x74  // 't'
463#define STK_READ_SIGN       0x75  // 'u'
464
465/** Task to read in AVR910 commands from the CDC data OUT endpoint, process them, perform the required actions
466 *  and send the appropriate response back to the host.
467 */
468void CDC_Task(void)
469{
470        /* Select the OUT endpoint */
471        Endpoint_SelectEndpoint(CDC_RX_EPNUM);
472
473        /* Check if endpoint has a command in it sent from the host */
474        if (!(Endpoint_IsOUTReceived()))
475          return;
476         
477        RX_LED_ON();
478        RxLEDPulse = TX_RX_LED_PULSE_PERIOD;
479
480        /* Read in the bootloader command (first byte sent from host) */
481        uint8_t Command = FetchNextCommandByte();
482
483        if (Command == 'E')
484        {
485                /* We nearly run out the bootloader timeout clock,
486                * leaving just a few hundred milliseconds so the
487                * bootloder has time to respond and service any
488                * subsequent requests */
489                Timeout = TIMEOUT_PERIOD - 500;
490       
491                /* Re-enable RWW section - must be done here in case
492                 * user has disabled verification on upload.  */
493                boot_rww_enable_safe();         
494
495                // Send confirmation byte back to the host
496                WriteNextResponseByte('\r');
497        }
498        else if (Command == 'T')
499        {
500                FetchNextCommandByte();
501
502                // Send confirmation byte back to the host
503                WriteNextResponseByte('\r');
504        }
505        else if ((Command == 'L') || (Command == 'P'))
506        {
507                // Send confirmation byte back to the host
508                WriteNextResponseByte('\r');
509        }
510        else if (Command == 't')
511        {
512                // Return ATMEGA128 part code - this is only to allow AVRProg to use the bootloader
513                WriteNextResponseByte(0x44);
514                WriteNextResponseByte(0x00);
515        }
516        else if (Command == 'a')
517        {
518                // Indicate auto-address increment is supported
519                WriteNextResponseByte('Y');
520        }
521        else if (Command == 'A')
522        {
523                // Set the current address to that given by the host
524                CurrAddress   = (FetchNextCommandByte() << 9);
525                CurrAddress  |= (FetchNextCommandByte() << 1);
526
527                // Send confirmation byte back to the host
528                WriteNextResponseByte('\r');
529        }
530        else if (Command == 'p')
531        {
532                // Indicate serial programmer back to the host
533                WriteNextResponseByte('S');
534        }
535        else if (Command == 'S')
536        {
537                // Write the 7-byte software identifier to the endpoint
538                for (uint8_t CurrByte = 0; CurrByte < 7; CurrByte++)
539                  WriteNextResponseByte(SOFTWARE_IDENTIFIER[CurrByte]);
540        }
541        else if (Command == 'V')
542        {
543                WriteNextResponseByte('0' + BOOTLOADER_VERSION_MAJOR);
544                WriteNextResponseByte('0' + BOOTLOADER_VERSION_MINOR);
545        }
546        else if (Command == 's')
547        {
548                WriteNextResponseByte(AVR_SIGNATURE_3);
549                WriteNextResponseByte(AVR_SIGNATURE_2);
550                WriteNextResponseByte(AVR_SIGNATURE_1);
551        }
552        else if (Command == 'e')
553        {
554                // Clear the application section of flash
555                for (uint32_t CurrFlashAddress = 0; CurrFlashAddress < BOOT_START_ADDR; CurrFlashAddress += SPM_PAGESIZE)
556                {
557                        boot_page_erase(CurrFlashAddress);
558                        boot_spm_busy_wait();
559                        boot_page_write(CurrFlashAddress);
560                        boot_spm_busy_wait();
561                }
562
563                // Send confirmation byte back to the host
564                WriteNextResponseByte('\r');
565        }
566        #if !defined(NO_LOCK_BYTE_WRITE_SUPPORT)
567        else if (Command == 'l')
568        {
569                // Set the lock bits to those given by the host
570                boot_lock_bits_set(FetchNextCommandByte());
571
572                // Send confirmation byte back to the host
573                WriteNextResponseByte('\r');
574        }
575        #endif
576        else if (Command == 'r')
577        {
578                WriteNextResponseByte(boot_lock_fuse_bits_get(GET_LOCK_BITS));
579        }
580        else if (Command == 'F')
581        {
582                WriteNextResponseByte(boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS));
583        }
584        else if (Command == 'N')
585        {
586                WriteNextResponseByte(boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS));
587        }
588        else if (Command == 'Q')
589        {
590                WriteNextResponseByte(boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS));
591        }
592        #if !defined(NO_BLOCK_SUPPORT)
593        else if (Command == 'b')
594        {
595                WriteNextResponseByte('Y');
596
597                // Send block size to the host
598                WriteNextResponseByte(SPM_PAGESIZE >> 8);
599                WriteNextResponseByte(SPM_PAGESIZE & 0xFF);
600        }
601        else if ((Command == 'B') || (Command == 'g'))
602        {
603                // Keep resetting the timeout counter if we're receiving self-programming instructions
604                Timeout = 0;
605                // Delegate the block write/read to a separate function for clarity
606                ReadWriteMemoryBlock(Command);
607        }
608        #endif
609        #if !defined(NO_FLASH_BYTE_SUPPORT)
610        else if (Command == 'C')
611        {
612                // Write the high byte to the current flash page
613                boot_page_fill(CurrAddress, FetchNextCommandByte());
614
615                // Send confirmation byte back to the host
616                WriteNextResponseByte('\r');
617        }
618        else if (Command == 'c')
619        {
620                // Write the low byte to the current flash page
621                boot_page_fill(CurrAddress | 0x01, FetchNextCommandByte());
622
623                // Increment the address
624                CurrAddress += 2;
625
626                // Send confirmation byte back to the host
627                WriteNextResponseByte('\r');
628        }
629        else if (Command == 'm')
630        {
631                // Commit the flash page to memory
632                boot_page_write(CurrAddress);
633
634                // Wait until write operation has completed
635                boot_spm_busy_wait();
636
637                // Send confirmation byte back to the host
638                WriteNextResponseByte('\r');
639        }
640        else if (Command == 'R')
641        {
642                #if (FLASHEND > 0xFFFF)
643                uint16_t ProgramWord = pgm_read_word_far(CurrAddress);
644                #else
645                uint16_t ProgramWord = pgm_read_word(CurrAddress);
646                #endif
647
648                WriteNextResponseByte(ProgramWord >> 8);
649                WriteNextResponseByte(ProgramWord & 0xFF);
650        }
651        #endif
652        #if !defined(NO_EEPROM_BYTE_SUPPORT)
653        else if (Command == 'D')
654        {
655                // Read the byte from the endpoint and write it to the EEPROM
656                eeprom_write_byte((uint8_t*)((intptr_t)(CurrAddress >> 1)), FetchNextCommandByte());
657
658                // Increment the address after use
659                CurrAddress += 2;
660
661                // Send confirmation byte back to the host
662                WriteNextResponseByte('\r');
663        }
664        else if (Command == 'd')
665        {
666                // Read the EEPROM byte and write it to the endpoint
667                WriteNextResponseByte(eeprom_read_byte((uint8_t*)((intptr_t)(CurrAddress >> 1))));
668
669                // Increment the address after use
670                CurrAddress += 2;
671        }
672        #endif
673        else if (Command != 27)
674        {
675                // Unknown (non-sync) command, return fail code
676                WriteNextResponseByte('?');
677        }
678       
679
680        /* Select the IN endpoint */
681        Endpoint_SelectEndpoint(CDC_TX_EPNUM);
682
683        /* Remember if the endpoint is completely full before clearing it */
684        bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed());
685
686        /* Send the endpoint data to the host */
687        Endpoint_ClearIN();
688
689        /* If a full endpoint's worth of data was sent, we need to send an empty packet afterwards to signal end of transfer */
690        if (IsEndpointFull)
691        {
692                while (!(Endpoint_IsINReady()))
693                {
694                        if (USB_DeviceState == DEVICE_STATE_Unattached)
695                          return;
696                }
697
698                Endpoint_ClearIN();
699        }
700
701        /* Wait until the data has been sent to the host */
702        while (!(Endpoint_IsINReady()))
703        {
704                if (USB_DeviceState == DEVICE_STATE_Unattached)
705                  return;
706        }
707
708        /* Select the OUT endpoint */
709        Endpoint_SelectEndpoint(CDC_RX_EPNUM);
710
711        /* Acknowledge the command from the host */
712        Endpoint_ClearOUT();
713}
714
Note: See TracBrowser for help on using the repository browser.