X-Git-Url: http://git.linex4red.de/pub/USBasp.git/blobdiff_plain/df9b04c87fa803d2237c407ba17845fe1ca53674..95ba6527a5e764a430c3917b4e24e48699976fa9:/Bootloaders/Printer/BootloaderPrinter.c diff --git a/Bootloaders/Printer/BootloaderPrinter.c b/Bootloaders/Printer/BootloaderPrinter.c index 7741f8087..023ec3e93 100644 --- a/Bootloaders/Printer/BootloaderPrinter.c +++ b/Bootloaders/Printer/BootloaderPrinter.c @@ -35,6 +35,35 @@ #include "BootloaderPrinter.h" +/** LUFA Printer Class driver interface configuration and state information. This structure is + * passed to all Printer Class driver functions, so that multiple instances of the same class + * within a device can be differentiated from one another. + */ +USB_ClassInfo_PRNT_Device_t TextOnly_Printer_Interface = + { + .Config = + { + .InterfaceNumber = 0, + .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", + }, + }; + /** Intel HEX parser state machine state information, to track the contents of * a HEX file streamed in as a sequence of arbitrary bytes. */ @@ -73,6 +102,37 @@ struct */ static bool PageDirty = false; + +/** Flag to indicate if the bootloader should be running, or should exit and allow the application code to run + * via a soft reset. When cleared, the bootloader will abort, the USB interface will shut down and the application + * started via a forced watchdog reset. + */ +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. + */ +uint16_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)(); + } +} + /** * Determines if a given input byte of data is an ASCII encoded HEX value. * @@ -80,7 +140,7 @@ static bool PageDirty = false; * * \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) { @@ -255,6 +315,10 @@ static void ParseIntelHEXByte(const char ReadCharacter) PageDirty = false; } + /* If end of the HEX file reached, the bootloader should exit at next opportunity */ + if (HEXParser.RecordType == HEX_RECORD_TYPE_EndOfFile) + RunBootloader = false; + break; default: @@ -273,33 +337,43 @@ int main(void) LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); GlobalInterruptEnable(); - for (;;) + while (RunBootloader) { - USB_USBTask(); - - Endpoint_SelectEndpoint(PRINTER_OUT_EPADDR); + uint8_t BytesReceived = PRNT_Device_BytesReceived(&TextOnly_Printer_Interface); - /* Check if we have received new printer data from the host */ - if (Endpoint_IsOUTReceived()) { - LEDs_ToggleLEDs(LEDMASK_USB_BUSY); + if (BytesReceived) + { + LEDs_SetAllLEDs(LEDMASK_USB_BUSY); - /* Read all bytes of data from the host and parse them */ - while (Endpoint_IsReadWriteAllowed()) + while (BytesReceived--) { + int16_t ReceivedByte = PRNT_Device_ReceiveByte(&TextOnly_Printer_Interface); + /* Feed the next byte of data to the HEX parser */ - ParseIntelHEXByte(Endpoint_Read_8()); + ParseIntelHEXByte(ReceivedByte); } - /* Send an ACK to the host, ready for the next data packet */ - Endpoint_ClearOUT(); - LEDs_SetAllLEDs(LEDMASK_USB_READY); } + + PRNT_Device_USBTask(&TextOnly_Printer_Interface); + USB_USBTask(); } + + /* 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); + + for (;;); } /** 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); @@ -351,8 +425,7 @@ void EVENT_USB_Device_ConfigurationChanged(void) bool ConfigSuccess = true; /* Setup Printer Data Endpoints */ - ConfigSuccess &= Endpoint_ConfigureEndpoint(PRINTER_IN_EPADDR, EP_TYPE_BULK, PRINTER_IO_EPSIZE, 1); - ConfigSuccess &= Endpoint_ConfigureEndpoint(PRINTER_OUT_EPADDR, EP_TYPE_BULK, PRINTER_IO_EPSIZE, 1); + ConfigSuccess &= PRNT_Device_ConfigureEndpoints(&TextOnly_Printer_Interface); /* Indicate endpoint configuration success or failure */ LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR); @@ -364,44 +437,5 @@ void EVENT_USB_Device_ConfigurationChanged(void) */ void EVENT_USB_Device_ControlRequest(void) { - /* Process Printer specific control requests */ - switch (USB_ControlRequest.bRequest) - { - case PRNT_REQ_GetDeviceID: - if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) - { - /* Generic printer IEEE 1284 identification string, will bind to an in-built driver on - * Windows systems, and will fall-back to a text-only printer driver on *nix. - */ - const char PrinterIDString[] = - "MFG:Generic;" - "MDL:Generic_/_Text_Only;" - "CMD:1284.4;" - "CLS:PRINTER"; - - Endpoint_ClearSETUP(); - Endpoint_Write_16_BE(sizeof(PrinterIDString)); - Endpoint_Write_Control_Stream_LE(PrinterIDString, strlen(PrinterIDString)); - Endpoint_ClearStatusStage(); - } - - break; - case PRNT_REQ_GetPortStatus: - if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) - { - Endpoint_ClearSETUP(); - Endpoint_Write_8(PRNT_PORTSTATUS_NOTERROR | PRNT_PORTSTATUS_SELECT); - Endpoint_ClearStatusStage(); - } - - break; - case PRNT_REQ_SoftReset: - if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) - { - Endpoint_ClearSETUP(); - Endpoint_ClearStatusStage(); - } - - break; - } + PRNT_Device_ProcessControlRequest(&TextOnly_Printer_Interface); }