#include "BootloaderPrinter.h"
USB_ClassInfo_PRNT_Device_t TextOnly_Printer_Interface =
{
.Config =
{
.InterfaceNumber = INTERFACE_ID_Printer,
.DataINEndpoint =
{
.Address = PRINTER_IN_EPADDR,
.Size = PRINTER_IO_EPSIZE,
.Banks = 1,
},
.DataOUTEndpoint =
{
.Address = PRINTER_OUT_EPADDR,
.Size = PRINTER_IO_EPSIZE,
.Banks = 1,
},
.IEEE1284String =
"MFG:Generic;"
"MDL:Generic_/_Text_Only;"
"CMD:1284.4;"
"CLS:PRINTER",
},
};
static struct
{
uint8_t ParserState;
uint8_t PrevData;
uint8_t Data;
bool ReadMSB;
uint8_t RecordType;
uint8_t DataRem;
uint8_t Checksum;
flashaddr_t PageStartAddress;
flashaddr_t CurrBaseAddress;
flashaddr_t CurrAddress;
} HEXParser;
static bool PageDirty = false;
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)();
}
}
static int8_t HexToDecimal(const char Byte)
{
if ((Byte >= 'A') && (Byte <= 'F'))
return (10 + (Byte - 'A'));
else if ((Byte >= '0') && (Byte <= '9'))
return (Byte - '0');
return -1;
}
static void FlushPageIfRequired(void)
{
if (!PageDirty)
return;
uint32_t NewPageStartAddress = (HEXParser.CurrAddress & ~(SPM_PAGESIZE - 1));
if (HEXParser.PageStartAddress != NewPageStartAddress)
{
BootloaderAPI_WritePage(HEXParser.PageStartAddress);
HEXParser.PageStartAddress = NewPageStartAddress;
PageDirty = false;
}
}
static void ParseIntelHEXByte(const char ReadCharacter)
{
if ((HEXParser.ParserState == HEX_PARSE_STATE_WAIT_LINE) || (ReadCharacter == ':'))
{
HEXParser.Checksum = 0;
HEXParser.CurrAddress = HEXParser.CurrBaseAddress;
HEXParser.ReadMSB = false;
if (ReadCharacter == ':')
HEXParser.ParserState = HEX_PARSE_STATE_BYTE_COUNT;
return;
}
int8_t ReadCharacterDec = HexToDecimal(ReadCharacter);
if (ReadCharacterDec < 0)
return;
HEXParser.Data = (HEXParser.Data << 4) | ReadCharacterDec;
HEXParser.ReadMSB = !HEXParser.ReadMSB;
if (HEXParser.ReadMSB)
return;
if (HEXParser.ParserState != HEX_PARSE_STATE_CHECKSUM)
HEXParser.Checksum += HEXParser.Data;
switch (HEXParser.ParserState)
{
case HEX_PARSE_STATE_BYTE_COUNT:
HEXParser.DataRem = HEXParser.Data;
HEXParser.ParserState = HEX_PARSE_STATE_ADDRESS_HIGH;
break;
case HEX_PARSE_STATE_ADDRESS_HIGH:
HEXParser.CurrAddress += ((uint16_t)HEXParser.Data << 8);
HEXParser.ParserState = HEX_PARSE_STATE_ADDRESS_LOW;
break;
case HEX_PARSE_STATE_ADDRESS_LOW:
HEXParser.CurrAddress += HEXParser.Data;
HEXParser.ParserState = HEX_PARSE_STATE_RECORD_TYPE;
break;
case HEX_PARSE_STATE_RECORD_TYPE:
HEXParser.RecordType = HEXParser.Data;
HEXParser.ParserState = (HEXParser.DataRem ? HEX_PARSE_STATE_READ_DATA : HEX_PARSE_STATE_CHECKSUM);
break;
case HEX_PARSE_STATE_READ_DATA:
HEXParser.DataRem--;
if (HEXParser.CurrAddress >= BOOT_START_ADDR)
{
HEXParser.ParserState = HEX_PARSE_STATE_WAIT_LINE;
PageDirty = false;
return;
}
if (HEXParser.DataRem & 0x01)
{
HEXParser.PrevData = HEXParser.Data;
break;
}
uint16_t NewDataWord = ((uint16_t)HEXParser.Data << 8) | HEXParser.PrevData;
switch (HEXParser.RecordType)
{
case HEX_RECORD_TYPE_Data:
if (!(PageDirty))
{
BootloaderAPI_ErasePage(HEXParser.PageStartAddress);
PageDirty = true;
}
BootloaderAPI_FillWord(HEXParser.CurrAddress, NewDataWord);
HEXParser.CurrAddress += 2;
FlushPageIfRequired();
break;
case HEX_RECORD_TYPE_ExtendedSegmentAddress:
HEXParser.CurrBaseAddress = ((uint32_t)NewDataWord << 4);
break;
case HEX_RECORD_TYPE_ExtendedLinearAddress:
HEXParser.CurrBaseAddress = ((uint32_t)NewDataWord << 16);
break;
}
if (!HEXParser.DataRem)
HEXParser.ParserState = HEX_PARSE_STATE_CHECKSUM;
break;
case HEX_PARSE_STATE_CHECKSUM:
if (HEXParser.Data != ((~HEXParser.Checksum + 1) & 0xFF))
break;
FlushPageIfRequired();
if (HEXParser.RecordType == HEX_RECORD_TYPE_EndOfFile)
RunBootloader = false;
break;
default:
HEXParser.ParserState = HEX_PARSE_STATE_WAIT_LINE;
break;
}
}
int main(void)
{
SetupHardware();
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
GlobalInterruptEnable();
while (RunBootloader)
{
uint8_t BytesReceived = PRNT_Device_BytesReceived(&TextOnly_Printer_Interface);
if (BytesReceived)
{
LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
while (BytesReceived--)
{
int16_t ReceivedByte = PRNT_Device_ReceiveByte(&TextOnly_Printer_Interface);
ParseIntelHEXByte(ReceivedByte);
}
LEDs_SetAllLEDs(LEDMASK_USB_READY);
}
PRNT_Device_USBTask(&TextOnly_Printer_Interface);
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);
LEDs_Init();
USB_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_Connect(void)
{
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
}
void EVENT_USB_Device_Disconnect(void)
{
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
}
void EVENT_USB_Device_ConfigurationChanged(void)
{
bool ConfigSuccess = true;
ConfigSuccess &= PRNT_Device_ConfigureEndpoints(&TextOnly_Printer_Interface);
HEXParser.ParserState = HEX_PARSE_STATE_WAIT_LINE;
LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
}
void EVENT_USB_Device_ControlRequest(void)
{
PRNT_Device_ProcessControlRequest(&TextOnly_Printer_Interface);
}