Fixed Low Speed USB devices broken when using the library HID Class driver (thanks...
[pub/USBasp.git] / Bootloaders / Printer / BootloaderPrinter.c
index a913b33..9a6a8c2 100644 (file)
@@ -59,6 +59,8 @@ struct
        uint8_t  Checksum;
        /** Starting address of the last addressed FLASH page. */
        uint32_t PageStartAddress;
        uint8_t  Checksum;
        /** Starting address of the last addressed FLASH page. */
        uint32_t PageStartAddress;
+       /** Current 32-bit byte extended base address in FLASH being targeted. */
+       uint32_t CurrBaseAddress;
        /** Current 32-bit byte address in FLASH being targeted. */
        uint32_t CurrAddress;
 } HEXParser =
        /** Current 32-bit byte address in FLASH being targeted. */
        uint32_t CurrAddress;
 } HEXParser =
@@ -78,7 +80,7 @@ static bool PageDirty = false;
  *
  * \param[in] Byte  ASCII byte of data to check
  *
  *
  * \param[in] Byte  ASCII byte of data to check
  *
- * \return Boolean \c true if the input data is ASCII encoded HEX, false otherwise.
+ * \return Boolean \c true if the input data is ASCII encoded HEX, \c false otherwise.
  */
 static bool IsHex(const char Byte)
 {
  */
 static bool IsHex(const char Byte)
 {
@@ -113,28 +115,36 @@ static uint8_t HexToDecimal(const char Byte)
  */
 static void ParseIntelHEXByte(const char ReadCharacter)
 {
  */
 static void ParseIntelHEXByte(const char ReadCharacter)
 {
+       /* Reset the line parser while waiting for a new line to start */
        if ((HEXParser.ParserState == HEX_PARSE_STATE_WAIT_LINE) || (ReadCharacter == ':'))
        {
                HEXParser.Checksum     = 0;
        if ((HEXParser.ParserState == HEX_PARSE_STATE_WAIT_LINE) || (ReadCharacter == ':'))
        {
                HEXParser.Checksum     = 0;
-               HEXParser.CurrAddress &= ~0xFFFF;
+               HEXParser.CurrAddress  = HEXParser.CurrBaseAddress;
                HEXParser.ParserState  = HEX_PARSE_STATE_WAIT_LINE;
                HEXParser.ReadMSB      = false;
 
                HEXParser.ParserState  = HEX_PARSE_STATE_WAIT_LINE;
                HEXParser.ReadMSB      = false;
 
+               /* ASCII ':' indicates the start of a new HEX record */
                if (ReadCharacter == ':')
                  HEXParser.ParserState = HEX_PARSE_STATE_BYTE_COUNT;
 
                return;
        }
 
                if (ReadCharacter == ':')
                  HEXParser.ParserState = HEX_PARSE_STATE_BYTE_COUNT;
 
                return;
        }
 
+       /* Only allow ASCII HEX encoded digits, ignore all other characters */
        if (!IsHex(ReadCharacter))
          return;
 
        if (!IsHex(ReadCharacter))
          return;
 
+       /* Read and convert the next nibble of data from the current character */
        HEXParser.Data    = (HEXParser.Data << 4) | HexToDecimal(ReadCharacter);
        HEXParser.ReadMSB = !HEXParser.ReadMSB;
 
        HEXParser.Data    = (HEXParser.Data << 4) | HexToDecimal(ReadCharacter);
        HEXParser.ReadMSB = !HEXParser.ReadMSB;
 
+       /* Only process further when a full byte (two nibbles) have been read */
        if (HEXParser.ReadMSB)
          return;
 
        if (HEXParser.ReadMSB)
          return;
 
+       /* Intel HEX checksum is for all fields except starting character and the
+        * checksum itself
+        */
        if (HEXParser.ParserState != HEX_PARSE_STATE_CHECKSUM)
          HEXParser.Checksum += HEXParser.Data;
 
        if (HEXParser.ParserState != HEX_PARSE_STATE_CHECKSUM)
          HEXParser.Checksum += HEXParser.Data;
 
@@ -146,12 +156,12 @@ static void ParseIntelHEXByte(const char ReadCharacter)
                        break;
 
                case HEX_PARSE_STATE_ADDRESS_HIGH:
                        break;
 
                case HEX_PARSE_STATE_ADDRESS_HIGH:
-                       HEXParser.CurrAddress |= ((uint16_t)HEXParser.Data << 8);
+                       HEXParser.CurrAddress += ((uint16_t)HEXParser.Data << 8);
                        HEXParser.ParserState  = HEX_PARSE_STATE_ADDRESS_LOW;
                        break;
 
                case HEX_PARSE_STATE_ADDRESS_LOW:
                        HEXParser.ParserState  = HEX_PARSE_STATE_ADDRESS_LOW;
                        break;
 
                case HEX_PARSE_STATE_ADDRESS_LOW:
-                       HEXParser.CurrAddress |= HEXParser.Data;
+                       HEXParser.CurrAddress += HEXParser.Data;
                        HEXParser.ParserState  = HEX_PARSE_STATE_RECORD_TYPE;
                        break;
 
                        HEXParser.ParserState  = HEX_PARSE_STATE_RECORD_TYPE;
                        break;
 
@@ -161,17 +171,33 @@ static void ParseIntelHEXByte(const char ReadCharacter)
                        break;
 
                case HEX_PARSE_STATE_READ_DATA:
                        break;
 
                case HEX_PARSE_STATE_READ_DATA:
+                       /* Track the number of read data bytes in the record */
                        HEXParser.DataRem--;
 
                        HEXParser.DataRem--;
 
+                       /* Protect the bootloader against being written to */
+                       if (HEXParser.CurrAddress >= BOOT_START_ADDR)
+                       {
+                               HEXParser.ParserState = HEX_PARSE_STATE_WAIT_LINE;
+                               PageDirty = false;
+                               return;
+                       }
+
+                       /* Wait for a machine word (two bytes) of data to be read */
                        if (HEXParser.DataRem & 0x01)
                        {
                                HEXParser.PrevData = HEXParser.Data;
                                break;
                        }
 
                        if (HEXParser.DataRem & 0x01)
                        {
                                HEXParser.PrevData = HEXParser.Data;
                                break;
                        }
 
+                       /* Convert the last two received data bytes into a 16-bit word */
+                       uint16_t NewDataWord = ((uint16_t)HEXParser.Data << 8) | HEXParser.PrevData;
+
                        switch (HEXParser.RecordType)
                        {
                                case HEX_RECORD_TYPE_Data:
                        switch (HEXParser.RecordType)
                        {
                                case HEX_RECORD_TYPE_Data:
+                                       /* If we are writing to a new page, we need to erase it
+                                        * first
+                                        */
                                        if (!(PageDirty))
                                        {
                                                boot_page_erase(HEXParser.PageStartAddress);
                                        if (!(PageDirty))
                                        {
                                                boot_page_erase(HEXParser.PageStartAddress);
@@ -180,9 +206,11 @@ static void ParseIntelHEXByte(const char ReadCharacter)
                                                PageDirty = true;
                                        }
 
                                                PageDirty = true;
                                        }
 
-                                       boot_page_fill(HEXParser.CurrAddress, ((uint16_t)HEXParser.Data << 8) | HEXParser.PrevData);
+                                       /* Fill the FLASH memory buffer with the new word of data */
+                                       boot_page_fill(HEXParser.CurrAddress, NewDataWord);
                                        HEXParser.CurrAddress += 2;
 
                                        HEXParser.CurrAddress += 2;
 
+                                       /* Flush the FLASH page to physical memory if we are crossing a page boundary */
                                        uint32_t NewPageStartAddress = (HEXParser.CurrAddress & ~(SPM_PAGESIZE - 1));
                                        if (PageDirty && (HEXParser.PageStartAddress != NewPageStartAddress))
                                        {
                                        uint32_t NewPageStartAddress = (HEXParser.CurrAddress & ~(SPM_PAGESIZE - 1));
                                        if (PageDirty && (HEXParser.PageStartAddress != NewPageStartAddress))
                                        {
@@ -195,8 +223,14 @@ static void ParseIntelHEXByte(const char ReadCharacter)
                                        }
                                        break;
 
                                        }
                                        break;
 
+                               case HEX_RECORD_TYPE_ExtendedSegmentAddress:
+                                       /* Extended address data - store the upper 12-bits of the new address */
+                                       HEXParser.CurrBaseAddress = ((uint32_t)NewDataWord << 4);
+                                       break;
+
                                case HEX_RECORD_TYPE_ExtendedLinearAddress:
                                case HEX_RECORD_TYPE_ExtendedLinearAddress:
-                                       HEXParser.CurrAddress |= (uint32_t)HEXParser.Data << (HEXParser.DataRem ? 24 : 16);
+                                       /* Extended address data - store the upper 16-bits of the new address */
+                                       HEXParser.CurrBaseAddress = ((uint32_t)NewDataWord << 16);
                                        break;
                        }
 
                                        break;
                        }
 
@@ -205,9 +239,11 @@ static void ParseIntelHEXByte(const char ReadCharacter)
                        break;
 
                case HEX_PARSE_STATE_CHECKSUM:
                        break;
 
                case HEX_PARSE_STATE_CHECKSUM:
+                       /* Verify checksum of the completed record */
                        if (HEXParser.Data != ((~HEXParser.Checksum + 1) & 0xFF))
                          break;
 
                        if (HEXParser.Data != ((~HEXParser.Checksum + 1) & 0xFF))
                          break;
 
+                       /* Flush the FLASH page to physical memory if we are crossing a page boundary */
                        uint32_t NewPageStartAddress = (HEXParser.CurrAddress & ~(SPM_PAGESIZE - 1));
                        if (PageDirty && (HEXParser.PageStartAddress != NewPageStartAddress))
                        {
                        uint32_t NewPageStartAddress = (HEXParser.CurrAddress & ~(SPM_PAGESIZE - 1));
                        if (PageDirty && (HEXParser.PageStartAddress != NewPageStartAddress))
                        {
@@ -263,7 +299,7 @@ int main(void)
 }
 
 /** Configures the board hardware and chip peripherals for the demo's functionality. */
 }
 
 /** Configures the board hardware and chip peripherals for the demo's functionality. */
-void SetupHardware(void)
+static void SetupHardware(void)
 {
        /* Disable watchdog if enabled by bootloader/fuses */
        MCUSR &= ~(1 << WDRF);
 {
        /* Disable watchdog if enabled by bootloader/fuses */
        MCUSR &= ~(1 << WDRF);
@@ -279,6 +315,16 @@ void SetupHardware(void)
        /* Hardware Initialization */
        LEDs_Init();
        USB_Init();
        /* Hardware Initialization */
        LEDs_Init();
        USB_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_Connect event. This indicates that the device is enumerating via the status LEDs. */
 }
 
 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs. */
@@ -289,7 +335,7 @@ void EVENT_USB_Device_Connect(void)
 }
 
 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
 }
 
 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
- *  the status LEDs and stops the Mass Storage management task.
+ *  the status LEDs and stops the Printer management task.
  */
 void EVENT_USB_Device_Disconnect(void)
 {
  */
 void EVENT_USB_Device_Disconnect(void)
 {