diff options
-rw-r--r-- | arcin/config.h | 15 | ||||
-rw-r--r-- | arcin/configloader.h | 86 | ||||
-rw-r--r-- | arcin/main.cpp | 373 | ||||
-rw-r--r-- | arcin/report_desc.h | 197 | ||||
-rw-r--r-- | arcin/usb_strings.h | 92 |
5 files changed, 395 insertions, 368 deletions
diff --git a/arcin/config.h b/arcin/config.h new file mode 100644 index 0000000..a851e9c --- /dev/null +++ b/arcin/config.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include <stdint.h> + +struct config_t { + uint8_t label[12]; + uint32_t flags; + int8_t qe1_sens; + int8_t qe2_sens; + uint8_t ps2_mode; + uint8_t ws2812b_mode; +}; + +#endif diff --git a/arcin/configloader.h b/arcin/configloader.h new file mode 100644 index 0000000..0963a01 --- /dev/null +++ b/arcin/configloader.h @@ -0,0 +1,86 @@ +#ifndef CONFIGLOADER_H +#define CONFIGLOADER_H + +#include <rcc/flash.h> +#include <string.h> + +class Configloader { + private: + enum { + MAGIC = 0xc0ff600d, + }; + + struct header_t { + uint32_t magic; + uint32_t size; + }; + + uint32_t flash_addr; + + public: + Configloader(uint32_t addr) : flash_addr(addr) {} + + bool read(uint32_t size, void* data) { + header_t* header = (header_t*)flash_addr; + + if(header->magic != MAGIC) { + return false; + } + + if(header->size < size) { + size = header->size; + } + + memcpy(data, (void*)(flash_addr + sizeof(header_t)), size); + + return true; + } + + bool write(uint32_t size, void* data) { + header_t header = {MAGIC, size}; + + // Unlock flash. + FLASH.KEYR = 0x45670123; + FLASH.KEYR = 0xCDEF89AB; + + // Erase page. + FLASH.CR = 1 << 1; // PER + FLASH.AR = flash_addr; + FLASH.CR = (1 << 6) | (1 << 1); // STRT, PER + + while(FLASH.SR & (1 << 0)); // BSY + + FLASH.SR &= ~(1 << 5); // EOP + FLASH.CR = 0; + + // Write header. + uint16_t* src = (uint16_t*)&header; + uint16_t* dest = (uint16_t*)flash_addr; + + for(uint32_t n = 0; n < sizeof(header); n += 2) { + FLASH.CR = 1 << 0; // PG + + *dest++ = *src++; + + while(FLASH.SR & (1 << 0)); // BSY + } + + // Write data. + src = (uint16_t*)data; + + for(uint32_t n = 0; n < size; n += 2) { + FLASH.CR = 1 << 0; // PG + + *dest++ = *src++; + + while(FLASH.SR & (1 << 0)); // BSY + } + + // Lock flash. + FLASH.CR = 1 << 7; // LOCK + + return true; + } +}; + +#endif diff --git a/arcin/main.cpp b/arcin/main.cpp index 5294b29..8f6abc3 100644 --- a/arcin/main.cpp +++ b/arcin/main.cpp @@ -1,14 +1,15 @@ #include <rcc/rcc.h> -#include <rcc/flash.h> #include <gpio/gpio.h> #include <interrupt/interrupt.h> #include <timer/timer.h> #include <os/time.h> #include <usb/usb.h> #include <usb/descriptor.h> -#include <usb/hid.h> -#include <string.h> +#include "report_desc.h" +#include "usb_strings.h" +#include "configloader.h" +#include "config.h" static uint32_t& reset_reason = *(uint32_t*)0x10000000; @@ -24,289 +25,10 @@ void reset_bootloader() { reset(); } -class Configloader { - private: - enum { - MAGIC = 0xc0ff600d, - }; - - struct header_t { - uint32_t magic; - uint32_t size; - }; - - uint32_t flash_addr; - - public: - Configloader(uint32_t addr) : flash_addr(addr) {} - - bool read(uint32_t size, void* data) { - header_t* header = (header_t*)flash_addr; - - if(header->magic != MAGIC) { - return false; - } - - if(header->size < size) { - size = header->size; - } - - memcpy(data, (void*)(flash_addr + sizeof(header_t)), size); - - return true; - } - - bool write(uint32_t size, void* data) { - header_t header = {MAGIC, size}; - - // Unlock flash. - FLASH.KEYR = 0x45670123; - FLASH.KEYR = 0xCDEF89AB; - - // Erase page. - FLASH.CR = 1 << 1; // PER - FLASH.AR = flash_addr; - FLASH.CR = (1 << 6) | (1 << 1); // STRT, PER - - while(FLASH.SR & (1 << 0)); // BSY - - FLASH.SR &= ~(1 << 5); // EOP - FLASH.CR = 0; - - // Write header. - uint16_t* src = (uint16_t*)&header; - uint16_t* dest = (uint16_t*)flash_addr; - - for(uint32_t n = 0; n < sizeof(header); n += 2) { - FLASH.CR = 1 << 0; // PG - - *dest++ = *src++; - - while(FLASH.SR & (1 << 0)); // BSY - } - - // Write data. - src = (uint16_t*)data; - - for(uint32_t n = 0; n < size; n += 2) { - FLASH.CR = 1 << 0; // PG - - *dest++ = *src++; - - while(FLASH.SR & (1 << 0)); // BSY - } - - // Lock flash. - FLASH.CR = 1 << 7; // LOCK - - return true; - } -}; - Configloader configloader(0x801f800); -struct config_t { - uint8_t label[12]; - uint32_t flags; - int8_t qe1_sens; - int8_t qe2_sens; - uint8_t ps2_mode; - uint8_t ws2812b_mode; -}; - config_t config; -auto report_desc = gamepad( - // Inputs. - report_id(1), - - buttons(15), - padding_in(1), - - usage_page(UsagePage::Desktop), - usage(DesktopUsage::X), - logical_minimum(0), - logical_maximum(255), - report_count(1), - report_size(8), - input(0x02), - - usage_page(UsagePage::Desktop), - usage(DesktopUsage::Y), - logical_minimum(0), - logical_maximum(255), - report_count(1), - report_size(8), - input(0x02), - - // Outputs. - report_id(2), - - usage_page(UsagePage::Ordinal), - usage(1), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - usage_page(UsagePage::Ordinal), - usage(2), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - usage_page(UsagePage::Ordinal), - usage(3), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - usage_page(UsagePage::Ordinal), - usage(4), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - usage_page(UsagePage::Ordinal), - usage(5), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - usage_page(UsagePage::Ordinal), - usage(6), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - usage_page(UsagePage::Ordinal), - usage(7), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - usage_page(UsagePage::Ordinal), - usage(8), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - usage_page(UsagePage::Ordinal), - usage(9), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - usage_page(UsagePage::Ordinal), - usage(10), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - usage_page(UsagePage::Ordinal), - usage(11), - collection(Collection::Logical, - usage_page(UsagePage::LED), - usage(0x4b), - report_size(1), - report_count(1), - output(0x02) - ), - - padding_out(5), - - // Bootloader - report_id(0xb0), - - usage_page(0xff55), - usage(0xb007), - logical_minimum(0), - logical_maximum(255), - report_size(8), - report_count(1), - - feature(0x02), // HID bootloader function - - // Configuration - report_id(0xc0), - - usage(0xc000), - feature(0x02), // Config segment - - usage(0xc001), - feature(0x02), // Config segment size - - feature(0x01), // Padding - - usage(0xc0ff), - report_count(60), - feature(0x02) // Config data -); - -struct input_report_t { - uint8_t report_id; - uint16_t buttons; - uint8_t axis_x; - uint8_t axis_y; -} __attribute__((packed)); - -struct output_report_t { - uint8_t report_id; - uint16_t leds; -} __attribute__((packed)); - -struct bootloader_report_t { - uint8_t report_id; - uint8_t func; -} __attribute__((packed)); - -struct config_report_t { - uint8_t report_id; - uint8_t segment; - uint8_t size; - uint8_t pad; - uint8_t data[60]; -} __attribute__((packed)); - auto dev_desc = device_desc(0x200, 0, 0, 0, 64, 0x1d50, 0x6080, 0x110, 1, 2, 3, 1); auto conf_desc = configuration_desc(1, 1, 0, 0xc0, 0, // HID interface. @@ -429,92 +151,7 @@ class HID_arcin : public USB_HID { HID_arcin usb_hid(usb, report_desc_p); -uint32_t serial_num() { - uint32_t* uid = (uint32_t*)0x1ffff7ac; - - return uid[0] * uid[1] * uid[2]; -} - -class USB_strings : public USB_class_driver { - private: - USB_generic& usb; - - public: - USB_strings(USB_generic& usbd) : usb(usbd) { - usb.register_driver(this); - } - - protected: - virtual SetupStatus handle_setup(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength) { - // Get string descriptor. - if(bmRequestType == 0x80 && bRequest == 0x06 && (wValue & 0xff00) == 0x0300) { - const void* desc = nullptr; - uint16_t buf[64] = {0x300}; - uint32_t i = 1; - - switch(wValue & 0xff) { - case 0: - desc = u"\u0304\u0409"; - break; - - case 1: - desc = u"\u0308zyp"; - break; - - case 2: - for(const char* p = "arcin"; *p; p++) { - buf[i++] = *p; - } - - if(config.label[0]) { - buf[i++] = ' '; - buf[i++] = '('; - - for(uint8_t* p = config.label; *p; p++) { - buf[i++] = *p; - } - - buf[i++] = ')'; - } - - buf[0] |= i * 2; - - desc = buf; - break; - - case 3: - { - buf[0] = 0x0312; - uint32_t id = serial_num(); - for(int i = 8; i > 0; i--) { - buf[i] = (id & 0xf) > 9 ? 'A' + (id & 0xf) - 0xa : '0' + (id & 0xf); - id >>= 4; - } - desc = buf; - } - break; - } - - if(!desc) { - return SetupStatus::Unhandled; - } - - uint8_t len = *(uint8_t*)desc; - - if(len > wLength) { - len = wLength; - } - - usb.write(0, (uint32_t*)desc, len); - - return SetupStatus::Ok; - } - - return SetupStatus::Unhandled; - } -}; - -USB_strings usb_strings(usb); +USB_strings usb_strings(usb, config.label); int main() { rcc_init(); diff --git a/arcin/report_desc.h b/arcin/report_desc.h new file mode 100644 index 0000000..b9602b7 --- /dev/null +++ b/arcin/report_desc.h @@ -0,0 +1,197 @@ +#ifndef REPORT_DESC_H +#define REPORT_DESC_H + +#include <usb/hid.h> + +auto report_desc = gamepad( + // Inputs. + report_id(1), + + buttons(15), + padding_in(1), + + usage_page(UsagePage::Desktop), + usage(DesktopUsage::X), + logical_minimum(0), + logical_maximum(255), + report_count(1), + report_size(8), + input(0x02), + + usage_page(UsagePage::Desktop), + usage(DesktopUsage::Y), + logical_minimum(0), + logical_maximum(255), + report_count(1), + report_size(8), + input(0x02), + + // Outputs. + report_id(2), + + usage_page(UsagePage::Ordinal), + usage(1), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + usage_page(UsagePage::Ordinal), + usage(2), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + usage_page(UsagePage::Ordinal), + usage(3), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + usage_page(UsagePage::Ordinal), + usage(4), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + usage_page(UsagePage::Ordinal), + usage(5), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + usage_page(UsagePage::Ordinal), + usage(6), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + usage_page(UsagePage::Ordinal), + usage(7), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + usage_page(UsagePage::Ordinal), + usage(8), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + usage_page(UsagePage::Ordinal), + usage(9), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + usage_page(UsagePage::Ordinal), + usage(10), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + usage_page(UsagePage::Ordinal), + usage(11), + collection(Collection::Logical, + usage_page(UsagePage::LED), + usage(0x4b), + report_size(1), + report_count(1), + output(0x02) + ), + + padding_out(5), + + // Bootloader + report_id(0xb0), + + usage_page(0xff55), + usage(0xb007), + logical_minimum(0), + logical_maximum(255), + report_size(8), + report_count(1), + + feature(0x02), // HID bootloader function + + // Configuration + report_id(0xc0), + + usage(0xc000), + feature(0x02), // Config segment + + usage(0xc001), + feature(0x02), // Config segment size + + feature(0x01), // Padding + + usage(0xc0ff), + report_count(60), + feature(0x02) // Config data +); + +struct input_report_t { + uint8_t report_id; + uint16_t buttons; + uint8_t axis_x; + uint8_t axis_y; +} __attribute__((packed)); + +struct output_report_t { + uint8_t report_id; + uint16_t leds; +} __attribute__((packed)); + +struct bootloader_report_t { + uint8_t report_id; + uint8_t func; +} __attribute__((packed)); + +struct config_report_t { + uint8_t report_id; + uint8_t segment; + uint8_t size; + uint8_t pad; + uint8_t data[60]; +} __attribute__((packed)); + +#endif diff --git a/arcin/usb_strings.h b/arcin/usb_strings.h new file mode 100644 index 0000000..6463ba4 --- /dev/null +++ b/arcin/usb_strings.h @@ -0,0 +1,92 @@ +#ifndef USB_STRINGS_H +#define USB_STRINGS_H + +#include <usb/usb.h> + +uint32_t serial_num() { + uint32_t* uid = (uint32_t*)0x1ffff7ac; + + return uid[0] * uid[1] * uid[2]; +} + +class USB_strings : public USB_class_driver { + private: + USB_generic& usb; + const uint8_t* label; + + public: + USB_strings(USB_generic& usbd, const uint8_t* l) : usb(usbd), label(l) { + usb.register_driver(this); + } + + protected: + virtual SetupStatus handle_setup(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength) { + // Get string descriptor. + if(bmRequestType == 0x80 && bRequest == 0x06 && (wValue & 0xff00) == 0x0300) { + const void* desc = nullptr; + uint16_t buf[64] = {0x300}; + uint32_t i = 1; + + switch(wValue & 0xff) { + case 0: + desc = u"\u0304\u0409"; + break; + + case 1: + desc = u"\u0308zyp"; + break; + + case 2: + for(const char* p = "arcin"; *p; p++) { + buf[i++] = *p; + } + + if(label[0]) { + buf[i++] = ' '; + buf[i++] = '('; + + for(const uint8_t* p = label; *p; p++) { + buf[i++] = *p; + } + + buf[i++] = ')'; + } + + buf[0] |= i * 2; + + desc = buf; + break; + + case 3: + { + buf[0] = 0x0312; + uint32_t id = serial_num(); + for(int i = 8; i > 0; i--) { + buf[i] = (id & 0xf) > 9 ? 'A' + (id & 0xf) - 0xa : '0' + (id & 0xf); + id >>= 4; + } + desc = buf; + } + break; + } + + if(!desc) { + return SetupStatus::Unhandled; + } + + uint8_t len = *(uint8_t*)desc; + + if(len > wLength) { + len = wLength; + } + + usb.write(0, (uint32_t*)desc, len); + + return SetupStatus::Ok; + } + + return SetupStatus::Unhandled; + } +}; + +#endif |