diff --git a/Firmware/Bootloader/Bootloader.c b/Firmware/Bootloader/Bootloader.c new file mode 100644 index 0000000..99192be --- /dev/null +++ b/Firmware/Bootloader/Bootloader.c @@ -0,0 +1,172 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2014. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Main source file for the HID class bootloader. This file contains the complete bootloader logic. + */ + +#include "Bootloader.h" + +/** 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; + +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) +{ + /* Always boot bootloader if RESET held + * NOTE: This makes the assumption that + * A) No code on the device uses RESET as an output + * B) The RSTDISBL fuse is set, and this value is valid + * C) There is an external pullup on the RESET pin + */ + if(!(PINC & _BV(1))) + return; + /* If power on boot or magic key set */ + if ((MCUSR & _BV(PORF)) || MagicBootKey == MAGIC_BOOT_KEY) + { + // If there's no code, this avoids an infinite reboot loop + MCUSR &= ~_BV(PORF); + // cppcheck-suppress constStatement + ((void (*)(void))0x0000)(); + } +} + +/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously + * runs the bootloader processing routine until instructed to soft-exit. + */ +int main(void) +{ + /* Setup hardware required for the bootloader */ + SetupHardware(); + + /* Enable global interrupts so that the USB stack can function */ + GlobalInterruptEnable(); + + while (RunBootloader) + 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 all hardware required for the bootloader. */ +static void SetupHardware(void) +{ + /* Disable watchdog if enabled by bootloader/fuses */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Relocate the interrupt vector table to the bootloader section */ + MCUCR = (1 << IVCE); + MCUCR = (1 << IVSEL); + + /* Initialize USB subsystem */ + USB_Init(); +} + +/** Event handler for the USB_ConfigurationChanged event. This configures the device's endpoints ready + * to relay data to and from the attached USB host. + */ +void EVENT_USB_Device_ConfigurationChanged(void) +{ + +} + +/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to + * the device from the USB host before passing along unhandled control requests to the library for processing + * internally. + */ +void EVENT_USB_Device_ControlRequest(void) +{ + Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP); + if(!Endpoint_IsSETUPReceived()) { + return; + } + if(USB_ControlRequest.bRequest == CONFIG_ID) { + Endpoint_ClearSETUP(); + uint16_t PageAddress = USB_ControlRequest.wValue; + if(USB_ControlRequest.wIndex == COMMAND_PROGRAM) { + /* Wait until the command has been sent by the host */ + while (!(Endpoint_IsOUTReceived())); + /* Erase the given FLASH page, ready to be programmed */ + boot_page_erase(PageAddress); + boot_spm_busy_wait(); + + /* Write each of the FLASH page's bytes in sequence */ + for (uint8_t PageWord = 0; PageWord < (SPM_PAGESIZE / 2); PageWord++) + { + /* Check if endpoint is empty - if so clear it and wait until ready for next packet */ + if (!(Endpoint_BytesInEndpoint())) + { + Endpoint_ClearOUT(); + while (!(Endpoint_IsOUTReceived())); + } + + /* Write the next data word to the FLASH page */ + boot_page_fill(PageAddress + ((uint16_t)PageWord << 1), Endpoint_Read_16_LE()); + } + + /* Write the filled FLASH page to memory */ + boot_page_write(PageAddress); + boot_spm_busy_wait(); + + /* Re-enable RWW section */ + boot_rww_enable(); + } else if(USB_ControlRequest.wIndex == COMMAND_VERSION) { + Endpoint_Write_16_LE(65000); + Endpoint_ClearIN(); + } else if(USB_ControlRequest.wIndex == COMMAND_STARTAPPLICATION) { + RunBootloader = false; + } + Endpoint_ClearOUT(); + Endpoint_ClearStatusStage(); + return; + } + + USB_Process_BOS(); +} \ No newline at end of file diff --git a/Firmware/Bootloader/Bootloader.h b/Firmware/Bootloader/Bootloader.h new file mode 100644 index 0000000..c6aaa90 --- /dev/null +++ b/Firmware/Bootloader/Bootloader.h @@ -0,0 +1,77 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2014. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for BootloaderHID.c. + */ + +#ifndef _BOOTLOADERHID_H_ +#define _BOOTLOADERHID_H_ + + /* Includes: */ + #include + #include + #include + #include + #include + #include + + #include "Descriptors.h" + + #include + #include + + /* Preprocessor Checks: */ + #if !defined(__OPTIMIZE_SIZE__) + #error This bootloader requires that it be optimized for size, not speed, to fit into the target device. Change optimization settings and try again. + #endif + + /* Macros: */ + /** Bootloader special address to start the user application */ + #define COMMAND_VERSION 0x03 + #define COMMAND_STARTAPPLICATION 0x04 + #define COMMAND_PROGRAM 0x05 + + #define BOOTLOADER_VERSION 65000 + + /** Magic bootloader key to unlock forced application start mode. */ + #define MAGIC_BOOT_KEY 0xDC42 + + /* Function Prototypes: */ + static void SetupHardware(void); + + void Application_Jump_Check(void) ATTR_INIT_SECTION(3); + + void EVENT_USB_Device_ConfigurationChanged(void); + void EVENT_USB_Device_UnhandledControlRequest(void); + +#endif + diff --git a/Firmware/PocketVoltex/DFU/control_bootloader.py b/Firmware/PocketVoltex/DFU/control_bootloader.py new file mode 100644 index 0000000..68b5881 --- /dev/null +++ b/Firmware/PocketVoltex/DFU/control_bootloader.py @@ -0,0 +1,145 @@ +""" + LUFA Library + Copyright (C) Dean Camera, 2014. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +""" + +""" + Front-end programmer for the LUFA HID class bootloader. + + Usage: + python hid_bootloader_loader.py .hex + + Example: + python hid_bootloader_loader.py at90usb1287 Mouse.hex + + Requires the pywinusb (https://pypi.python.org/pypi/pywinusb/) and + IntelHex (http://bialix.com/intelhex/) libraries. +""" + +import sys +from intelhex import IntelHex +import time + +# new bootloader +import usb1 + +ENDPOINT_SIZE = 32 + +WEBUSB_ID = 0x01 +MS_OS_ID = 0x02 +CONFIG_ID = 0x03 + +COMMAND_VERSION = 0x03 +COMMAND_STARTAPPLICATION = 0x04 +COMMAND_PROGRAM = 0x05 + +BOOTLOADER_VERSION = 65000 + +# Device information table +device_info_map = dict() +device_info_map['at90usb1287'] = {'page_size': 256, 'flash_kb': 128} +device_info_map['at90usb1286'] = {'page_size': 256, 'flash_kb': 128} +device_info_map['at90usb647'] = {'page_size': 256, 'flash_kb': 64} +device_info_map['at90usb646'] = {'page_size': 256, 'flash_kb': 64} +device_info_map['atmega32u4'] = {'page_size': 128, 'flash_kb': 32} +device_info_map['atmega32u2'] = {'page_size': 128, 'flash_kb': 32} +device_info_map['atmega16u4'] = {'page_size': 128, 'flash_kb': 16} +device_info_map['atmega16u2'] = {'page_size': 128, 'flash_kb': 16} +device_info_map['at90usb162'] = {'page_size': 128, 'flash_kb': 16} +device_info_map['atmega8u2'] = {'page_size': 128, 'flash_kb': 8} +device_info_map['at90usb82'] = {'page_size': 128, 'flash_kb': 8} + +def get_version(device): + ver = device.controlRead(usb1.libusb1.LIBUSB_REQUEST_TYPE_VENDOR | usb1.libusb1.LIBUSB_RECIPIENT_DEVICE, CONFIG_ID, 0, COMMAND_VERSION, 2) + return ver[0] | ver[1] << 8 + +def get_device_handle(context): + voltex = None + for dev in context.getDeviceList(): + if dev.getVendorID() == 0x16D0 and dev.getProductID() == 0x0A6D: + # because there is the pseudo-composite-parent we ignore + try: + voltex = dev.open() + print "Open success!" + except: + print "Open fail" + return voltex + +def bootloader_boot(device): + with device.claimInterface(0): + device.bulkWrite(1, [42] + [0]*(ENDPOINT_SIZE-1)) + return True + +def send_page_data(device, address, data): + device.controlWrite(usb1.libusb1.LIBUSB_REQUEST_TYPE_VENDOR | usb1.libusb1.LIBUSB_RECIPIENT_DEVICE, + CONFIG_ID, address, COMMAND_PROGRAM, data) + + +def program_device(hex_data, device_info): + context = usb1.USBContext() + device = get_device_handle(context) + + if device is None: + print("No valid device found.") + sys.exit(1) + + if get_version(device) != BOOTLOADER_VERSION: + print("Device not in bootloader. TODO: reboot") + sys.exit(1) + + try: + print("Connected to bootloader.") + + # Program in all data from the loaded HEX file, in a number of device + # page sized chunks + for addr in range(0, hex_data.maxaddr(), device_info['page_size']): + # Compute the address range of the current page in the device + current_page_range = range(addr, addr+device_info['page_size']) + + # Extract the data from the hex file at the specified start page + # address and convert it to a regular list of bytes + page_data = [hex_data[i] for i in current_page_range] + + print("Writing address 0x%04X-0x%04X" % (current_page_range[0], current_page_range[-1])) + + # Devices with more than 64KB of flash should shift down the page + # address so that it is 16-bit (page size is guaranteed to be + # >= 256 bytes so no non-zero address bits are discarded) + if device_info['flash_kb'] < 64: + send_page_data(device, addr, page_data) + else: + send_page_data(device, addr >> 8, page_data) + + # Once programming is complete, start the application via a dummy page + # program to the page address 0xFFFF + print("Programming complete, starting application.") + try: + device.controlWrite(usb1.libusb1.LIBUSB_REQUEST_TYPE_VENDOR | usb1.libusb1.LIBUSB_RECIPIENT_DEVICE, + CONFIG_ID, 0, COMMAND_STARTAPPLICATION, []) # reboot, ignore pipe error + except usb1.USBErrorPipe: + pass + + finally: + device.close() + context.close() + + +if __name__ == '__main__': + # Load the specified HEX file + try: + hex_data = IntelHex(sys.argv[2]) + except: + print("Could not open the specified HEX file.") + sys.exit(1) + + # Retrieve the device information entry for the specified device + try: + device_info = device_info_map[sys.argv[1]] + except: + print("Unknown device name specified.") + sys.exit(1) + + program_device(hex_data, device_info) diff --git a/Firmware/PocketVoltex/LogCurveGen.py b/Firmware/PocketVoltex/LogCurveGen.py new file mode 100644 index 0000000..8781c94 --- /dev/null +++ b/Firmware/PocketVoltex/LogCurveGen.py @@ -0,0 +1,18 @@ +from __future__ import print_function +import math + +BRIGHTNESS_LEVELS = 64 + +print("// Generated by LogCurveGen.py") +print("PROGMEM const static uint8_t ledLogCurve[] = {", end='') +for i in range(BRIGHTNESS_LEVELS): + # newline every 8 + if i % 8 == 0: + print("\n\t", end='') + if i == 0: + mapped = 0 + else: + mapped = int(math.log(i,BRIGHTNESS_LEVELS-1) * BRIGHTNESS_LEVELS) + # map to the different order in the board + print('{}, '.format(mapped), end='') +print("};") diff --git a/Firmware/PocketVoltex/fader.xlsx b/Firmware/PocketVoltex/fader.xlsx new file mode 100644 index 0000000..f63fae4 Binary files /dev/null and b/Firmware/PocketVoltex/fader.xlsx differ