#define INCLUDE_FROM_BOOTLOADERCDC_C
#include "BootloaderCDC.h"
static CDC_LineEncoding_t LineEncoding = { .BaudRateBPS = 0,
.CharFormat = CDC_LINEENCODING_OneStopBit,
.ParityType = CDC_PARITY_None,
.DataBits = 8 };
static uint32_t CurrAddress;
static bool RunBootloader = true;
uint16_t MagicBootKey ATTR_NO_INIT;
void Application_Jump_Check(void)
{
bool JumpToApplication = false;
#if (BOARD == BOARD_LEONARDO)
PORTC |= (1 << 7);
Delay_MS(10);
JumpToApplication = ((PINC & (1 << 7)) != 0);
PORTC &= ~(1 << 7);
#elif ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
JTAG_DISABLE();
PORTF |= (1 << 4);
Delay_MS(10);
JumpToApplication = ((PINF & (1 << 4)) != 0);
JTAG_ENABLE();
#else
if (!(BootloaderAPI_ReadFuse(GET_HIGH_FUSE_BITS) & ~FUSE_BOOTRST))
{
if (!(MCUSR & (1 << EXTRF)) || (MagicBootKey == MAGIC_BOOT_KEY))
JumpToApplication = true;
MCUSR &= ~(1 << EXTRF);
}
else
{
if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY))
JumpToApplication = true;
MCUSR &= ~(1 << WDRF);
}
#endif
bool ApplicationValid = (pgm_read_word_near(0) != 0xFFFF);
if (JumpToApplication && ApplicationValid)
{
MCUSR &= ~(1 << WDRF);
wdt_disable();
MagicBootKey = 0;
((void (*)(void))0x0000)();
}
}
int main(void)
{
SetupHardware();
LEDs_SetAllLEDs(LEDS_LED1);
GlobalInterruptEnable();
while (RunBootloader)
{
CDC_Task();
USB_USBTask();
}
_delay_us(1000);
USB_Detach();
MagicBootKey = MAGIC_BOOT_KEY;
wdt_enable(WDTO_250MS);
for (;;);
}
static void SetupHardware(void)
{
MCUSR &= ~(1 << WDRF);
wdt_disable();
clock_prescale_set(clock_div_1);
MCUCR = (1 << IVCE);
MCUCR = (1 << IVSEL);
USB_Init();
LEDs_Init();
TIMSK1 = (1 << TOIE1);
TCCR1B = ((1 << CS11) | (1 << CS10));
}
ISR(TIMER1_OVF_vect, ISR_BLOCK)
{
LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2);
}
void EVENT_USB_Device_ConfigurationChanged(void)
{
Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPADDR, EP_TYPE_INTERRUPT,
CDC_NOTIFICATION_EPSIZE, 1);
Endpoint_ConfigureEndpoint(CDC_TX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1);
Endpoint_ConfigureEndpoint(CDC_RX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1);
}
void EVENT_USB_Device_ControlRequest(void)
{
if ((USB_ControlRequest.bmRequestType & (CONTROL_REQTYPE_TYPE | CONTROL_REQTYPE_RECIPIENT)) !=
(REQTYPE_CLASS | REQREC_INTERFACE))
{
return;
}
LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2);
switch (USB_ControlRequest.bRequest)
{
case CDC_REQ_GetLineEncoding:
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
Endpoint_Write_Control_Stream_LE(&LineEncoding, sizeof(CDC_LineEncoding_t));
Endpoint_ClearOUT();
}
break;
case CDC_REQ_SetLineEncoding:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
Endpoint_Read_Control_Stream_LE(&LineEncoding, sizeof(CDC_LineEncoding_t));
Endpoint_ClearIN();
}
break;
case CDC_REQ_SetControlLineState:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
}
break;
}
}
#if !defined(NO_BLOCK_SUPPORT)
static void ReadWriteMemoryBlock(const uint8_t Command)
{
uint16_t BlockSize;
char MemoryType;
uint8_t HighByte = 0;
uint8_t LowByte = 0;
BlockSize = (FetchNextCommandByte() << 8);
BlockSize |= FetchNextCommandByte();
MemoryType = FetchNextCommandByte();
if ((MemoryType != MEMORY_TYPE_FLASH) && (MemoryType != MEMORY_TYPE_EEPROM))
{
WriteNextResponseByte('?');
return;
}
if (Command == AVR109_COMMAND_BlockRead)
{
while (BlockSize--)
{
if (MemoryType == MEMORY_TYPE_FLASH)
{
#if (FLASHEND > 0xFFFF)
WriteNextResponseByte(pgm_read_byte_far(CurrAddress | HighByte));
#else
WriteNextResponseByte(pgm_read_byte(CurrAddress | HighByte));
#endif
if (HighByte)
CurrAddress += 2;
HighByte = !HighByte;
}
else
{
WriteNextResponseByte(eeprom_read_byte((uint8_t*)(intptr_t)(CurrAddress >> 1)));
CurrAddress += 2;
}
}
}
else
{
uint32_t PageStartAddress = CurrAddress;
if (MemoryType == MEMORY_TYPE_FLASH)
BootloaderAPI_ErasePage(PageStartAddress);
while (BlockSize--)
{
if (MemoryType == MEMORY_TYPE_FLASH)
{
if (HighByte)
{
BootloaderAPI_FillWord(CurrAddress, ((FetchNextCommandByte() << 8) | LowByte));
CurrAddress += 2;
}
else
{
LowByte = FetchNextCommandByte();
}
HighByte = !HighByte;
}
else
{
eeprom_update_byte((uint8_t*)((intptr_t)(CurrAddress >> 1)), FetchNextCommandByte());
CurrAddress += 2;
}
}
if (MemoryType == MEMORY_TYPE_FLASH)
{
BootloaderAPI_WritePage(PageStartAddress);
}
WriteNextResponseByte('\r');
}
}
#endif
static uint8_t FetchNextCommandByte(void)
{
Endpoint_SelectEndpoint(CDC_RX_EPADDR);
while (!(Endpoint_IsReadWriteAllowed()))
{
Endpoint_ClearOUT();
while (!(Endpoint_IsOUTReceived()))
{
if (USB_DeviceState == DEVICE_STATE_Unattached)
return 0;
}
}
return Endpoint_Read_8();
}
static void WriteNextResponseByte(const uint8_t Response)
{
Endpoint_SelectEndpoint(CDC_TX_EPADDR);
if (!(Endpoint_IsReadWriteAllowed()))
{
Endpoint_ClearIN();
while (!(Endpoint_IsINReady()))
{
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
}
Endpoint_Write_8(Response);
}
static void CDC_Task(void)
{
Endpoint_SelectEndpoint(CDC_RX_EPADDR);
if (!(Endpoint_IsOUTReceived()))
return;
uint8_t Command = FetchNextCommandByte();
if (Command == AVR109_COMMAND_ExitBootloader)
{
RunBootloader = false;
WriteNextResponseByte('\r');
}
else if ((Command == AVR109_COMMAND_SetLED) || (Command == AVR109_COMMAND_ClearLED) ||
(Command == AVR109_COMMAND_SelectDeviceType))
{
FetchNextCommandByte();
WriteNextResponseByte('\r');
}
else if ((Command == AVR109_COMMAND_EnterProgrammingMode) || (Command == AVR109_COMMAND_LeaveProgrammingMode))
{
WriteNextResponseByte('\r');
}
else if (Command == AVR109_COMMAND_ReadPartCode)
{
WriteNextResponseByte(0x44);
WriteNextResponseByte(0x00);
}
else if (Command == AVR109_COMMAND_ReadAutoAddressIncrement)
{
WriteNextResponseByte('Y');
}
else if (Command == AVR109_COMMAND_SetCurrentAddress)
{
CurrAddress = ((uint32_t)FetchNextCommandByte() << 9);
CurrAddress |= ((uint32_t)FetchNextCommandByte() << 1);
WriteNextResponseByte('\r');
}
else if (Command == AVR109_COMMAND_ReadBootloaderInterface)
{
WriteNextResponseByte('S');
}
else if (Command == AVR109_COMMAND_ReadBootloaderIdentifier)
{
for (uint8_t CurrByte = 0; CurrByte < 7; CurrByte++)
WriteNextResponseByte(SOFTWARE_IDENTIFIER[CurrByte]);
}
else if (Command == AVR109_COMMAND_ReadBootloaderSWVersion)
{
WriteNextResponseByte('0' + BOOTLOADER_VERSION_MAJOR);
WriteNextResponseByte('0' + BOOTLOADER_VERSION_MINOR);
}
else if (Command == AVR109_COMMAND_ReadSignature)
{
WriteNextResponseByte(AVR_SIGNATURE_3);
WriteNextResponseByte(AVR_SIGNATURE_2);
WriteNextResponseByte(AVR_SIGNATURE_1);
}
else if (Command == AVR109_COMMAND_EraseFLASH)
{
for (uint32_t CurrFlashAddress = 0; CurrFlashAddress < (uint32_t)BOOT_START_ADDR; CurrFlashAddress += SPM_PAGESIZE)
BootloaderAPI_ErasePage(CurrFlashAddress);
WriteNextResponseByte('\r');
}
#if !defined(NO_LOCK_BYTE_WRITE_SUPPORT)
else if (Command == AVR109_COMMAND_WriteLockbits)
{
BootloaderAPI_WriteLock(FetchNextCommandByte());
WriteNextResponseByte('\r');
}
#endif
else if (Command == AVR109_COMMAND_ReadLockbits)
{
WriteNextResponseByte(BootloaderAPI_ReadLock());
}
else if (Command == AVR109_COMMAND_ReadLowFuses)
{
WriteNextResponseByte(BootloaderAPI_ReadFuse(GET_LOW_FUSE_BITS));
}
else if (Command == AVR109_COMMAND_ReadHighFuses)
{
WriteNextResponseByte(BootloaderAPI_ReadFuse(GET_HIGH_FUSE_BITS));
}
else if (Command == AVR109_COMMAND_ReadExtendedFuses)
{
WriteNextResponseByte(BootloaderAPI_ReadFuse(GET_EXTENDED_FUSE_BITS));
}
#if !defined(NO_BLOCK_SUPPORT)
else if (Command == AVR109_COMMAND_GetBlockWriteSupport)
{
WriteNextResponseByte('Y');
WriteNextResponseByte(SPM_PAGESIZE >> 8);
WriteNextResponseByte(SPM_PAGESIZE & 0xFF);
}
else if ((Command == AVR109_COMMAND_BlockWrite) || (Command == AVR109_COMMAND_BlockRead))
{
ReadWriteMemoryBlock(Command);
}
#endif
#if !defined(NO_FLASH_BYTE_SUPPORT)
else if (Command == AVR109_COMMAND_FillFlashPageWordHigh)
{
BootloaderAPI_FillWord(CurrAddress, FetchNextCommandByte());
WriteNextResponseByte('\r');
}
else if (Command == AVR109_COMMAND_FillFlashPageWordLow)
{
BootloaderAPI_FillWord(CurrAddress | 0x01, FetchNextCommandByte());
CurrAddress += 2;
WriteNextResponseByte('\r');
}
else if (Command == AVR109_COMMAND_WriteFlashPage)
{
BootloaderAPI_WritePage(CurrAddress);
WriteNextResponseByte('\r');
}
else if (Command == AVR109_COMMAND_ReadFLASHWord)
{
#if (FLASHEND > 0xFFFF)
uint16_t ProgramWord = pgm_read_word_far(CurrAddress);
#else
uint16_t ProgramWord = pgm_read_word(CurrAddress);
#endif
WriteNextResponseByte(ProgramWord >> 8);
WriteNextResponseByte(ProgramWord & 0xFF);
}
#endif
#if !defined(NO_EEPROM_BYTE_SUPPORT)
else if (Command == AVR109_COMMAND_WriteEEPROM)
{
eeprom_update_byte((uint8_t*)((intptr_t)(CurrAddress >> 1)), FetchNextCommandByte());
CurrAddress += 2;
WriteNextResponseByte('\r');
}
else if (Command == AVR109_COMMAND_ReadEEPROM)
{
WriteNextResponseByte(eeprom_read_byte((uint8_t*)((intptr_t)(CurrAddress >> 1))));
CurrAddress += 2;
}
#endif
else if (Command != AVR109_COMMAND_Sync)
{
WriteNextResponseByte('?');
}
Endpoint_SelectEndpoint(CDC_TX_EPADDR);
bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed());
Endpoint_ClearIN();
if (IsEndpointFull)
{
while (!(Endpoint_IsINReady()))
{
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
Endpoint_ClearIN();
}
while (!(Endpoint_IsINReady()))
{
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
Endpoint_SelectEndpoint(CDC_RX_EPADDR);
Endpoint_ClearOUT();
}