#include #include #include #include "usb.h" #include "unique-id.h" #include "eeprom.h" #include volatile unsigned int i = 0x12345678; unsigned char c = 2; unsigned int my_static_var; volatile uint32_t tick = 0; uint8_t ep0_buff[64]; uint8_t dev_descriptor[] = { 18, // bLength 1, // bDescriptorType 0x00, 0x02, // bcdUSB 0x00, // bDeviceClass = Use info in interface descriptor 0x00, // bDeviceSubClass = Use info in interface 0x00, // bDeviceProtocol = Use info in interface 64, // bMaxPacketSize0 0xAD, 0xDE, // idVendor 0xEF, 0xBE, // idProduct 0x00, 0x01, // bcdDevice 1, // iManufacturer 2, // iProduct 3, // iSerialNumber 1 // bNumConfigurations }; /* See: https://github.com/anszom/avr-vusb-keyboard/blob/master/sw/hid_descriptor.h */ const uint8_t hid_report_descriptor[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x81, 0x02, // INPUT (Data,Var,Abs) //1 byte 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Cnst,Var,Abs) //1 byte 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x65, // LOGICAL_MAXIMUM (101) 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 0x81, 0x00, // INPUT (Data,Ary,Abs) //6 bytes 0xc0 // END_COLLECTION }; struct hid_report { uint8_t modifier; uint8_t reserved; uint8_t keycodes[6]; }; const uint8_t config_desc[34] = { 9, /* bLenght */ 2, /* bDescriptorType */ 34, 0, /* wTotalLength */ 1, /* bNumInterfaces */ 1, /* bConfigurationValue */ 0, /* iConfiguration */ 0x80, /* bmAttributes */ 50, /* bMaxPower */ /* Interface Descriptor */ 0x09, /* Length = 9 */ 0x04, /* Type = Interface Descriptor */ 0x00, /* Interface Number */ 0x00, /* bAlternateSetting */ 0x01, /* bNumEndpoints */ 0x03, /* bInterfaceClass (3 = HID) */ 0x00, /* bInterfaceSubClass */ 0x00, /* bInterfaceProtocol */ 0x00, /* iInterface */ /* Endpoint Descriptor: EP1 Interrupt IN */ 0x07, /* bLength */ 0x05, /* bDescriptorType (5 = endpoint) */ 0x81, /* bEndpointAddress */ 0x03, /* bmAttributes (3 = Interrupt transfer */ 64, 0x00, /* MaxPacketSize */ 10, /* bInterval */ /* HID Descriptor */ 9, /* bLength */ 0x21, /* Descriptor Type: 0x21 = HID */ 0x11, 0x01, /* BCD HID */ 0x00, /* bCountryCode */ 1, /* bNumDescriptors */ 0x22, /* bDescriptorType 0x22=report */ sizeof(hid_report_descriptor), 0x00 }; const uint8_t lang_zero_desc[4] = { 4, /* bLength */ 3, /* Descriptor Type = string */ 0x09, 0x04 /* Language ID = English (US) */ }; const uint8_t manufacturer_string_desc[] = { 2 + 8 * 2, /* Length */ 3, /* Type = String descriptor */ 'S', 0x00, 'h', 0x00, 'i', 0x00, 'm', 0x00, 'a', 0x00, 't', 0x00, 't', 0x00, 'a', 0x00, }; const uint8_t product_string_desc[] = { 2 + 22 * 2, /* Length */ 3, /* Type = String descriptor */ 'S', 0x00, 'u', 0x00, 's', 0x00, 't', 0x00, 'a', 0x00, 'i', 0x00, 'n', 0x00, ' ', 0x00, 'P', 0x00, 'e', 0x00, 'd', 0x00, 'a', 0x00, 'l', 0x00, ' ', 0x00, 'K', 0x00, 'e', 0x00, 'y', 0x00, 'b', 0x00, 'o', 0x00, 'a', 0x00, 'r', 0x00, 'd', 0x00, }; uint8_t serial_string_desc[25 * 2 + 10]; struct usb_descriptor_entry desc_table[] = { {0x0000, 0x0100, dev_descriptor, sizeof(dev_descriptor)}, {0x0000, 0x0200, config_desc, sizeof(config_desc)}, {0x0000, 0x0300, lang_zero_desc, sizeof(lang_zero_desc)}, {0x0409, 0x0301, manufacturer_string_desc, sizeof(manufacturer_string_desc)}, {0x0409, 0x0302, product_string_desc, sizeof(product_string_desc)}, {0x0409, 0x0303, serial_string_desc, sizeof(serial_string_desc)}, {0x0000, 0x2200, hid_report_descriptor, sizeof(hid_report_descriptor)}, {0x0001, 0x2200, hid_report_descriptor, sizeof(hid_report_descriptor)}, /* sentinel */ {0x00, 0x0, NULL, 0}, }; static void wait_for_ticks(uint32_t ticks) { tick = 0; while (tick < ticks); } static void uint_to_hex(uint64_t num, uint8_t hex_digits, char *out) { int pos; int string_idx; uint64_t mask; if (!out || !hex_digits) return; if (hex_digits > 16) return; for (pos = hex_digits - 1, string_idx = 0; pos >= 0; pos--, string_idx++) { mask = num & ((uint64_t)0xFULL << (pos * 4)); mask >>= pos * 4; if (mask <= 0x9) { out[string_idx] = 0x30 + (char)mask; } else if (mask > 0x9) { out[string_idx] = 0x37 + mask; } } } static void create_sn_from_unique_id(void) { uint64_t lot; uint32_t uid; char id_string[25]; int i; int j; struct usb_descriptor_entry *desc_entry; unique_id_get(&lot, &uid); uint_to_hex(lot, 16, id_string); id_string[16] = ':'; uint_to_hex(uid, 8, &id_string[17]); for (i = 0; desc_table[i].descriptor; i++) { desc_entry = &desc_table[i]; if (desc_entry->descriptor == serial_string_desc) { for (j = 0; j < 25; j++) { serial_string_desc[2 * j + 2] = id_string[j]; serial_string_desc[2 * j + 1 + 2] = 0x00; } desc_entry->size = 25 * 2 + 2; serial_string_desc[0] = 25 * 2 + 2; serial_string_desc[1] = 3; break; } } } bool expect_report; bool expect_eeprom_data; uint16_t eep_offset; uint16_t eep_len; static void ep_rx_data_callback(uint8_t endpoint, const uint8_t *buffer, uint32_t len) { if (endpoint == 0) { if (expect_report) { usb_endpoint_send_status_stage(0); } else if (expect_eeprom_data) { if (len > eep_len) { usb_endpoint_stall(0, true, true); } else { data_eeprom_write(eep_offset, buffer, len); eep_len -= len; eep_offset += len; if (eep_len == 0) { usb_endpoint_send_status_stage(0); } } } } return; } static void append_pedal_keycodes_to_report(struct hid_report *r, uint32_t word) { int i, j; uint8_t keycode; if (word & 0xFF) { r->modifier |= word & 0xFF; } for (i = 0; i < 3; i++) { word >>= 8; keycode = word & 0xFF; if (!keycode) continue; for (j = 0; j < 6; j++) { if (r->keycodes[j] == 0) { r->keycodes[j] = keycode; break; } } } } static void build_report(struct hid_report *r) { uint32_t idr; const uint32_t *pedal1_word = (const uint32_t *)0x08080000UL; const uint32_t *pedal2_word = (const uint32_t *)0x08080004UL; idr = GPIOB->IDR; memset(r, 0, sizeof(struct hid_report)); if (!(idr & (1<<7))) { append_pedal_keycodes_to_report(r, *pedal1_word); } if (!(idr & (1<<6))) { append_pedal_keycodes_to_report(r, *pedal2_word); } } static uint16_t idle; static enum control_state ep_rx_setup_received_callback(uint8_t endpoint, const struct setup_packet *setup_pkg) { enum control_state ret_state = CONTROL_NOT_HANDLED; static struct hid_report r; expect_report = false; expect_eeprom_data = false; eep_len = 0; eep_offset = 0; if (endpoint != 0) { return ret_state; } if (setup_pkg->bm_req_type & 0x80) { /* Device to host transfer */ if ((setup_pkg->bm_req_type & 0xE0) == 0x20) { /* Class transfer */ switch (setup_pkg->b_request) { case 0x01: /* Get report */ build_report(&r); usb_endpoint_send(0, (uint8_t *)&r, sizeof(r)); ret_state = CONTROL_DATA_TX; break; case 0x02: /* Get idle */ usb_endpoint_send(0, (uint8_t *)&idle, 2); break; } } else if (setup_pkg->bm_req_type & (1<<6)) { switch (setup_pkg->b_request) { case 0x2: usb_endpoint_send(0, (uint8_t *)0x08080000, setup_pkg->w_length); ret_state = CONTROL_DATA_TX; break; } } } else { /* Host to device transfer */ if ((setup_pkg->bm_req_type & 0xE0) == 0x20) { /* Class transfer */ switch (setup_pkg->b_request) { case 0xA: /* Set idle */ idle = setup_pkg->w_value; ret_state = CONTROL_STATUS_TX; break; case 0x09: /* Set report */ expect_report = true; usb_endpoint_prepare_receive(0, ep0_buff, sizeof(ep0_buff)); ret_state = CONTROL_DATA_RX; break; default: break; } } else if (setup_pkg->bm_req_type == 0x1 && setup_pkg->b_request == 11) { /* Set interface */ /* Nothing to do. Just ack it */ ret_state = CONTROL_STATUS_TX; } else if (setup_pkg->bm_req_type == (1<<6)) { /* Vendor Access */ switch (setup_pkg->b_request) { case 0x1: if (setup_pkg->w_value) GPIOA->ODR |= (1<w_index); else GPIOA->ODR &= ~(1<w_index); ret_state = CONTROL_STATUS_TX; break; case 0x2: expect_eeprom_data = true; eep_len = setup_pkg->w_length; eep_offset = setup_pkg->w_index; usb_endpoint_prepare_receive(0, ep0_buff, sizeof(ep0_buff)); ret_state = CONTROL_DATA_RX; break; default: break; } } } return ret_state; } static volatile bool ep1_tx_pending; static void ep_tx_complete_callback(uint8_t endpoint) { if (endpoint == 1) { ep1_tx_pending = false; } else if (endpoint == 0) { } } static void usb_sof_callback(void) { } static volatile bool configured = false; static void usb_reset_callback(void) { configured = false; } static void usb_configured_callback(uint16_t config_idx) { GPIOA->ODR &= ~0xF; usb_endpoint_config(EP_INTERRUPT, 1, false, true); configured = true; } const struct usb_callbacks my_callbacks = { .ep_rx_data_callback = ep_rx_data_callback, .ep_rx_setup_received_callback = ep_rx_setup_received_callback, .ep_tx_complete_callback = ep_tx_complete_callback, .usb_configured_callback = usb_configured_callback, .usb_reset_callback = usb_reset_callback, .usb_sof_callback = usb_sof_callback, }; static void patch_vid_pid() { const uint32_t * const vid_pid_ptr = (const uint32_t *)0x08080008; const uint32_t vid_pid_word = *vid_pid_ptr; uint16_t vid; uint16_t pid; vid = (vid_pid_word >> 16) & 0xFFFFU; pid = vid_pid_word & 0xFFFF; if (vid != 0U && pid != 0U) { dev_descriptor[8] = (uint8_t)(vid & 0xFF); dev_descriptor[9] = (uint8_t)((vid >> 8) & 0xFF); dev_descriptor[10] = (uint8_t)(pid & 0xFF); dev_descriptor[11] = (uint8_t)((pid >> 8) & 0xFF); } } int main(void) { bool status_changed = false; struct hid_report report; struct hid_report report_send_buff; RCC->IOPENR |= RCC_IOPENR_IOPAEN; GPIOA->MODER &= ~(3<<(0*2)) & ~(3<<(1*2)) & ~(3<<(2*2)) & ~(3<<(3*2)); GPIOA->MODER |= (1<<(0*2)) | (1<<(1*2)) | (1<<(2*2)) | (1<<(3*2)); GPIOA->ODR |= (1<<0); SysTick_Config(3200000); //setup_usb_clock(); __enable_irq(); create_sn_from_unique_id(); patch_vid_pid(); usb_init(&my_callbacks); wait_for_ticks(2); usb_enable(desc_table); NVIC_SetPriority(SysTick_IRQn, 0); NVIC_SetPriority(USB_IRQn, 1); RCC->IOPENR |= RCC_IOPENR_GPIOBEN; GPIOB->MODER &= ~((0x3<<(6*2)) | (0x3<<(7*2))); GPIOB->PUPDR |= (1<<(6*2)) | (1<<(7*2)); while (1) { while (!configured) { ep1_tx_pending = false; } build_report(&report); if (memcmp(&report, &report_send_buff, sizeof(struct hid_report))) status_changed = true; if (status_changed && !ep1_tx_pending) { memcpy(&report_send_buff, &report, sizeof(struct hid_report)); ep1_tx_pending = true; status_changed = false; usb_endpoint_send(1, (uint8_t *)&report_send_buff, sizeof(struct hid_report)); } } } void SysTick_Handler(void) { tick++; }