diff --git a/firmware/fadecandy.cpp b/firmware/fadecandy.cpp index 17da6c9b269881cae778c70d4d03987aed5c903e..501fc95540b86238910331177aa005a68be92bf7 100644 --- a/firmware/fadecandy.cpp +++ b/firmware/fadecandy.cpp @@ -38,6 +38,9 @@ static OctoWS2811z leds(LEDS_PER_STRIP, ledBuffer, WS2811_800kHz); // Residuals for temporal dithering static int8_t residual[CHANNELS_TOTAL]; +// Reserved RAM area for signalling entry to bootloader +extern uint32_t boot_token; + static inline uint32_t calculateInterpCoefficient() { @@ -443,12 +446,30 @@ static void updateDrawBuffer(unsigned interpCoefficient) } } +void dfu_reboot() +{ + // Reboot to the Fadecandy Bootloader + boot_token = 0x74624346; + + // Short delay to allow the host to receive the response to DFU_DETACH. + uint32_t deadline = millis() + 10; + while (millis() < deadline) { + watchdog_refresh(); + } + + // Detach from USB, and use the watchdog to time out a 10ms USB disconnect. + __disable_irq(); + USB0_CONTROL = 0; + while (1); +} + extern "C" int main() { pinMode(LED_BUILTIN, OUTPUT); leds.begin(); - while (1) { + // Application main loop + while (usb_dfu_state == DFU_appIDLE) { watchdog_refresh(); buffers.handleUSB(); @@ -460,4 +481,7 @@ extern "C" int main() memset(residual, 0, sizeof residual); } } + + // Reboot into DFU bootloader + dfu_reboot(); } diff --git a/firmware/usb_desc.c b/firmware/usb_desc.c index b8e0263c24de8f44822b44aa6114d1972d0f3760..a9aa22bd83cbab75de4747202b97680c90935236 100644 --- a/firmware/usb_desc.c +++ b/firmware/usb_desc.c @@ -132,6 +132,27 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { 0, // bInterval #endif // FC_INTERFACE +#ifdef DFU_INTERFACE + // interface descriptor, DFU Mode (DFU spec Table 4.4) + 9, // bLength + 4, // bDescriptorType + DFU_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 0, // bNumEndpoints + 0xFE, // bInterfaceClass + 0x01, // bInterfaceSubClass + 0x01, // bInterfaceProtocol (Runtime) + 4, // iInterface + // DFU Functional Descriptor (DFU spec TAble 4.2) + 9, // bLength + 0x21, // bDescriptorType + 0x0D, // bmAttributes + LSB(DFU_DETACH_TIMEOUT), // wDetachTimeOut + MSB(DFU_DETACH_TIMEOUT), + LSB(DFU_TRANSFER_SIZE), // wTransferSize + MSB(DFU_TRANSFER_SIZE), + 0x01,0x01, // bcdDFUVersion +#endif // DFU_INTERFACE }; @@ -174,6 +195,11 @@ struct usb_string_descriptor_struct usb_string_product_name_default = { 3, PRODUCT_NAME }; +struct usb_string_descriptor_struct usb_string_dfu_name = { + 2 + DFU_NAME_LEN * 2, + 3, + DFU_NAME +}; // 32-digit hex string, corresponding to the MK20DX128's built-in unique 128-bit ID. struct usb_string_descriptor_struct usb_string_serial_number_default = { @@ -232,37 +258,11 @@ const usb_descriptor_list_t usb_descriptor_list[] = { //wValue, wIndex, address, length {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, {0x0200, 0x0000, config_descriptor, sizeof(config_descriptor)}, -#ifdef SEREMU_INTERFACE - {0x2200, SEREMU_INTERFACE, seremu_report_desc, sizeof(seremu_report_desc)}, - {0x2100, SEREMU_INTERFACE, config_descriptor+SEREMU_DESC_OFFSET, 9}, -#endif -#ifdef KEYBOARD_INTERFACE - {0x2200, KEYBOARD_INTERFACE, keyboard_report_desc, sizeof(keyboard_report_desc)}, - {0x2100, KEYBOARD_INTERFACE, config_descriptor+KEYBOARD_DESC_OFFSET, 9}, -#endif -#ifdef MOUSE_INTERFACE - {0x2200, MOUSE_INTERFACE, mouse_report_desc, sizeof(mouse_report_desc)}, - {0x2100, MOUSE_INTERFACE, config_descriptor+MOUSE_DESC_OFFSET, 9}, -#endif -#ifdef JOYSTICK_INTERFACE - {0x2200, JOYSTICK_INTERFACE, joystick_report_desc, sizeof(joystick_report_desc)}, - {0x2100, JOYSTICK_INTERFACE, config_descriptor+JOYSTICK_DESC_OFFSET, 9}, -#endif -#ifdef RAWHID_INTERFACE - {0x2200, RAWHID_INTERFACE, rawhid_report_desc, sizeof(rawhid_report_desc)}, - {0x2100, RAWHID_INTERFACE, config_descriptor+RAWHID_DESC_OFFSET, 9}, -#endif -#ifdef FLIGHTSIM_INTERFACE - {0x2200, FLIGHTSIM_INTERFACE, flightsim_report_desc, sizeof(flightsim_report_desc)}, - {0x2100, FLIGHTSIM_INTERFACE, config_descriptor+FLIGHTSIM_DESC_OFFSET, 9}, -#endif {0x0300, 0x0000, (const uint8_t *)&string0, 0}, {0x0301, 0x0409, (const uint8_t *)&usb_string_manufacturer_name, 0}, {0x0302, 0x0409, (const uint8_t *)&usb_string_product_name, 0}, {0x0303, 0x0409, (const uint8_t *)&usb_string_serial_number, 0}, - //{0x0301, 0x0409, (const uint8_t *)&string1, 0}, - //{0x0302, 0x0409, (const uint8_t *)&string2, 0}, - //{0x0303, 0x0409, (const uint8_t *)&string3, 0}, + {0x0304, 0x0409, (const uint8_t *)&usb_string_dfu_name, 0}, {0, 0, NULL, 0} }; @@ -271,20 +271,6 @@ const usb_descriptor_list_t usb_descriptor_list[] = { // Endpoint Configuration // ************************************************************** -#if 0 -// 0x00 = not used -// 0x19 = Recieve only -// 0x15 = Transmit only -// 0x1D = Transmit & Recieve -// -const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS] = -{ - 0x00, 0x15, 0x19, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -#endif - - const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS] = { #if (defined(ENDPOINT1_CONFIG) && NUM_ENDPOINTS >= 1) diff --git a/firmware/usb_desc.h b/firmware/usb_desc.h index bc2231fa014f0f35c58e2cf08b108fd606ba6b6b..81efa8de33e6c089991c4d7e57ba765747f46c69 100644 --- a/firmware/usb_desc.h +++ b/firmware/usb_desc.h @@ -82,19 +82,24 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports */ #define USB_FADECANDY - #define DEVICE_VER 0x0101 + #define DEVICE_VER 0x0102 #define DEVICE_CLASS 0xff // Vendor specific #define MANUFACTURER_NAME {'s','c','a','n','l','i','m','e'} #define MANUFACTURER_NAME_LEN 8 #define PRODUCT_NAME {'F','a','d','e','c','a','n','d','y'} #define PRODUCT_NAME_LEN 9 + #define DFU_NAME {'F','a','d','e','c','a','n','d','y',' ','B','o','o','t','l','o','a','d','e','r'} + #define DFU_NAME_LEN 20 #define EP0_SIZE 64 #define NUM_ENDPOINTS 1 - #define NUM_INTERFACE 1 + #define NUM_INTERFACE 2 #define FC_INTERFACE 0 #define FC_OUT_ENDPOINT 1 #define FC_OUT_SIZE 64 - #define CONFIG_DESC_SIZE (9+9+7) + #define DFU_INTERFACE 1 + #define DFU_DETACH_TIMEOUT 10000 // 10 seconds + #define DFU_TRANSFER_SIZE 1024 // Flash sector size + #define CONFIG_DESC_SIZE (9+9+7+9+9) #define ENDPOINT1_CONFIG ENDPOINT_RECEIVE_ONLY // NUM_ENDPOINTS = number of non-zero endpoints (0 to 15) diff --git a/firmware/usb_dev.c b/firmware/usb_dev.c index 84676dfa2283930fa7c1c9fc506eca5c5fdc757e..3a67abc9fd6441d2f5988eb13fb520a8b20b4854 100644 --- a/firmware/usb_dev.c +++ b/firmware/usb_dev.c @@ -1,4 +1,8 @@ -/* Teensyduino Core Library +/* + * Fadecandy firmware + * Copyright (c) 2013 Micah Elizabeth Scott + * + * Teensyduino Core Library * http://www.pjrc.com/teensy/ * Copyright (c) 2013 PJRC.COM, LLC. * @@ -123,7 +127,7 @@ static uint8_t ep0_tx_data_toggle = 0; uint8_t usb_rx_memory_needed = 0; volatile uint8_t usb_configuration = 0; - +volatile uint8_t usb_dfu_state = DFU_appIDLE; static void endpoint0_stall(void) { @@ -284,6 +288,39 @@ static void usb_setup(void) endpoint0_stall(); return; + case 0x03a1: // DFU_GETSTATUS + if (setup.wIndex != DFU_INTERFACE) { + endpoint0_stall(); + return; + } + reply_buffer[0] = 0; // bStatus = OK + reply_buffer[1] = 1; // bwPollTimeout LSB = 1 + reply_buffer[2] = 0; // bwPollTimeout + reply_buffer[3] = 0; // bwPollTimeout + reply_buffer[4] = usb_dfu_state; + reply_buffer[5] = 0; // iString = 0 + data = reply_buffer; + datalen = 6; + break; + + case 0x05a1: // DFU_GETSTATE + if (setup.wIndex != DFU_INTERFACE) { + endpoint0_stall(); + return; + } + reply_buffer[0] = usb_dfu_state; + data = reply_buffer; + datalen = 1; + break; + + case 0x0021: // DFU_DETACH + if (setup.wIndex != DFU_INTERFACE) { + endpoint0_stall(); + return; + } + usb_dfu_state = DFU_appDETACH; + break; + default: endpoint0_stall(); return; diff --git a/firmware/usb_dev.h b/firmware/usb_dev.h index 5122504367fc7460508e7d73f57f14f0c971af70..e22c2f9c4e6e841fa8ff5065b47c2cd3b46a752f 100644 --- a/firmware/usb_dev.h +++ b/firmware/usb_dev.h @@ -53,6 +53,11 @@ void usb_tx(uint32_t endpoint, usb_packet_t *packet); void usb_tx_isr(uint32_t endpoint, usb_packet_t *packet); extern volatile uint8_t usb_configuration; +extern volatile uint8_t usb_dfu_state; + +// DFU states +#define DFU_appIDLE 0 +#define DFU_appDETACH 1 extern uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; static inline uint32_t usb_rx_byte_count(uint32_t endpoint) __attribute__((always_inline));