X-Git-Url: http://git.linex4red.de/pub/USBasp.git/blobdiff_plain/cae0fa73d70f82820bd8d71c4d60b6aff8ccf3cb..f0af2e4a0280c43af3200909f6a00c2afaa65364:/Bootloaders/CDC/BootloaderCDC.c diff --git a/Bootloaders/CDC/BootloaderCDC.c b/Bootloaders/CDC/BootloaderCDC.c index cb6619edb..211b054e3 100644 --- a/Bootloaders/CDC/BootloaderCDC.c +++ b/Bootloaders/CDC/BootloaderCDC.c @@ -1,13 +1,13 @@ /* LUFA Library - Copyright (C) Dean Camera, 2011. + Copyright (C) Dean Camera, 2012. dean [at] fourwalledcubicle [dot] com www.lufa-lib.org */ /* - Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com) + Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com) Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted @@ -39,24 +39,46 @@ /** Contains the current baud rate and other settings of the first virtual serial port. This must be retained as some * operating systems will not open the port unless the settings can be set successfully. */ -CDC_Line_Coding_t LineEncoding = { .BaudRateBPS = 0, - .CharFormat = OneStopBit, - .ParityType = Parity_None, - .DataBits = 8 }; +static CDC_LineEncoding_t LineEncoding = { .BaudRateBPS = 0, + .CharFormat = CDC_LINEENCODING_OneStopBit, + .ParityType = CDC_PARITY_None, + .DataBits = 8 }; /** Current address counter. This stores the current address of the FLASH or EEPROM as set by the host, * and is used when reading or writing to the AVRs memory (either FLASH or EEPROM depending on the issued * command.) */ -uint32_t CurrAddress; +static uint32_t CurrAddress; /** Flag to indicate if the bootloader should be running, or should exit and allow the application code to run * via a watchdog reset. When cleared the bootloader will exit, starting the watchdog and entering an infinite * loop until the AVR restarts and the application runs. */ -bool RunBootloader = true; +static bool RunBootloader = true; + +/** Magic lock for forced application start. If the HWBE fuse is programmed and BOOTRST is unprogrammed, the bootloader + * will start if the /HWB line of the AVR is held low and the system is reset. However, if the /HWB line is still held + * low when the application attempts to start via a watchdog reset, the bootloader will re-start. If set to the value + * \ref MAGIC_BOOT_KEY the special init function \ref Application_Jump_Check() will force the application to start. + */ +uint32_t MagicBootKey ATTR_NO_INIT; +/** Special startup routine to check if the bootloader was started via a watchdog reset, and if the magic application + * start key has been loaded into \ref MagicBootKey. If the bootloader started via the watchdog and the key is valid, + * this will force the user application to start via a software jump. + */ +void Application_Jump_Check(void) +{ + /* If the reset source was the bootloader and the key is correct, clear it and jump to the application */ + if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY)) + { + MagicBootKey = 0; + // cppcheck-suppress constStatement + ((void (*)(void))0x0000)(); + } +} + /** 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. @@ -66,6 +88,9 @@ int main(void) /* Setup hardware required for the bootloader */ SetupHardware(); + /* 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(); @@ -77,6 +102,9 @@ int main(void) /* Disconnect from the host - USB interface will be reset later along with the AVR */ USB_Detach(); + + /* Unlock the forced application start mode of the bootloader if it is restarted */ + MagicBootKey = MAGIC_BOOT_KEY; /* Enable the watchdog and force a timeout to reset the AVR */ wdt_enable(WDTO_250MS); @@ -85,7 +113,7 @@ int main(void) } /** Configures all hardware required for the bootloader. */ -void SetupHardware(void) +static void SetupHardware(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); @@ -98,8 +126,19 @@ void SetupHardware(void) MCUCR = (1 << IVCE); MCUCR = (1 << IVSEL); - /* Initialize USB Subsystem */ + /* Initialize the USB and other board hardware drivers */ USB_Init(); + LEDs_Init(); + + /* Bootloader active LED toggle timer initialization */ + TIMSK1 = (1 << TOIE1); + TCCR1B = ((1 << CS11) | (1 << CS10)); +} + +/** 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_ConfigurationChanged event. This configures the device's endpoints ready @@ -108,17 +147,12 @@ void SetupHardware(void) void EVENT_USB_Device_ConfigurationChanged(void) { /* Setup CDC Notification, Rx and Tx Endpoints */ - Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE, - ENDPOINT_BANK_SINGLE); + Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPADDR, EP_TYPE_INTERRUPT, + CDC_NOTIFICATION_EPSIZE, 1); - Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK, - ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE, - ENDPOINT_BANK_SINGLE); + Endpoint_ConfigureEndpoint(CDC_TX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1); - Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK, - ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE, - ENDPOINT_BANK_SINGLE); + Endpoint_ConfigureEndpoint(CDC_RX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1); } /** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to @@ -134,27 +168,30 @@ void EVENT_USB_Device_ControlRequest(void) return; } + /* Activity - toggle indicator LEDs */ + LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2); + /* Process CDC specific control requests */ switch (USB_ControlRequest.bRequest) { - case REQ_GetLineEncoding: + case CDC_REQ_GetLineEncoding: if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) { Endpoint_ClearSETUP(); /* Write the line coding data to the control endpoint */ - Endpoint_Write_Control_Stream_LE(&LineEncoding, sizeof(CDC_Line_Coding_t)); + Endpoint_Write_Control_Stream_LE(&LineEncoding, sizeof(CDC_LineEncoding_t)); Endpoint_ClearOUT(); } break; - case REQ_SetLineEncoding: + case CDC_REQ_SetLineEncoding: if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) { Endpoint_ClearSETUP(); /* Read the line coding data in from the host into the global struct */ - Endpoint_Read_Control_Stream_LE(&LineEncoding, sizeof(CDC_Line_Coding_t)); + Endpoint_Read_Control_Stream_LE(&LineEncoding, sizeof(CDC_LineEncoding_t)); Endpoint_ClearIN(); } @@ -249,7 +286,7 @@ static void ReadWriteMemoryBlock(const uint8_t Command) { LowByte = FetchNextCommandByte(); } - + HighByte = !HighByte; } else @@ -286,7 +323,7 @@ static void ReadWriteMemoryBlock(const uint8_t Command) static uint8_t FetchNextCommandByte(void) { /* Select the OUT endpoint so that the next data byte can be read */ - Endpoint_SelectEndpoint(CDC_RX_EPNUM); + Endpoint_SelectEndpoint(CDC_RX_EPADDR); /* If OUT endpoint empty, clear it and wait for the next packet from the host */ while (!(Endpoint_IsReadWriteAllowed())) @@ -301,7 +338,7 @@ static uint8_t FetchNextCommandByte(void) } /* Fetch the next byte from the OUT endpoint */ - return Endpoint_Read_Byte(); + return Endpoint_Read_8(); } /** Writes the next response byte to the CDC data IN endpoint, and sends the endpoint back if needed to free up the @@ -312,7 +349,7 @@ static uint8_t FetchNextCommandByte(void) static void WriteNextResponseByte(const uint8_t Response) { /* Select the IN endpoint so that the next data byte can be written */ - Endpoint_SelectEndpoint(CDC_TX_EPNUM); + Endpoint_SelectEndpoint(CDC_TX_EPADDR); /* If IN endpoint full, clear it and wait until ready for the next packet to the host */ if (!(Endpoint_IsReadWriteAllowed())) @@ -327,16 +364,16 @@ static void WriteNextResponseByte(const uint8_t Response) } /* Write the next byte to the IN endpoint */ - Endpoint_Write_Byte(Response); + Endpoint_Write_8(Response); } /** Task to read in AVR910 commands from the CDC data OUT endpoint, process them, perform the required actions * and send the appropriate response back to the host. */ -void CDC_Task(void) +static void CDC_Task(void) { /* Select the OUT endpoint */ - Endpoint_SelectEndpoint(CDC_RX_EPNUM); + Endpoint_SelectEndpoint(CDC_RX_EPADDR); /* Check if endpoint has a command in it sent from the host */ if (!(Endpoint_IsOUTReceived())) @@ -348,7 +385,7 @@ void CDC_Task(void) if (Command == 'E') { RunBootloader = false; - + /* Send confirmation byte back to the host */ WriteNextResponseByte('\r'); } @@ -532,7 +569,7 @@ void CDC_Task(void) } /* Select the IN endpoint */ - Endpoint_SelectEndpoint(CDC_TX_EPNUM); + Endpoint_SelectEndpoint(CDC_TX_EPADDR); /* Remember if the endpoint is completely full before clearing it */ bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed()); @@ -560,7 +597,7 @@ void CDC_Task(void) } /* Select the OUT endpoint */ - Endpoint_SelectEndpoint(CDC_RX_EPNUM); + Endpoint_SelectEndpoint(CDC_RX_EPADDR); /* Acknowledge the command from the host */ Endpoint_ClearOUT();