#include "IIDXHID.h" #define BUTTON_PADDING (8 - (NUMBER_OF_BUTTONS % 8)) #define LED_PADDING (8 - (NUMBER_OF_LEDS % 8)) uint8_t usb_data[128]; uint16_t lamp_hid_state = 0; uint8_t extern led_pins[]; bool extern hid_reactive_autoswitch; /* HID string and device descriptor */ const DeviceDescriptor PROGMEM USB_DeviceDescriptorIAD = D_DEVICE(0xEF, 0x02, 0x01, 64, 0x1ccf, 0x8048, 0x100, IMANUFACTURER, IPRODUCT, ISERIAL, 1); const char* const PROGMEM String_Manufacturer = "Konami Amusement"; const char* const PROGMEM String_Product = "beatmania IIDX controller premium model"; const char* const PROGMEM String_Serial = "IIDX"; const char* const PROGMEM LEDString_00 = "Button 1"; const char* const PROGMEM LEDString_01 = "Button 2"; const char* const PROGMEM LEDString_02 = "Button 3"; const char* const PROGMEM LEDString_03 = "Button 4"; const char* const PROGMEM LEDString_04 = "Button 5"; const char* const PROGMEM LEDString_05 = "Button 6"; const char* const PROGMEM LEDString_06 = "Button 7"; const char* const PROGMEM LEDString_07 = "Misc button 1"; const char* const PROGMEM LEDString_08 = "Misc button 2"; const char* const PROGMEM LEDString_09 = "Misc button 3"; const char* const PROGMEM LEDString_10 = "Misc button 4"; const char* const PROGMEM TTString = "TT Sensitivity"; const char* String_indiv[] = { LEDString_00, LEDString_01, LEDString_02, LEDString_03, LEDString_04, LEDString_05, LEDString_06, LEDString_07, LEDString_08, LEDString_09, LEDString_10, TTString }; uint8_t STRING_ID_Count = 12; static const uint8_t PROGMEM hid_report[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x04, // USAGE (Joystick) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x05, // REPORT_ID (5) // HAT Switch (1 nibble) 0x05, 0x01, // USAGE_PAGE (HAT) 0x25, 0x07, // LOGICAL_MAXIMUM (7) 0x46, 0x3B, 0x01, // 0x75, 0x04, // REPORT_SIZE (4) 0x95, 0x01, // REPORT_COUNT (1) 0x65, 0x14, // UNIT (None) 0x09, 0x39, // USAGE (57) 0x81, 0x42, // INPUT (Data,Var,Abs) 0x65, 0x00, // UNIT (None) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x01, // INPUT (Data,Var,Abs) /* Buttons */ 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, NUMBER_OF_BUTTONS, // USAGE_MAXIMUM (Button NUMBER_OF_BUTTONS) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, NUMBER_OF_BUTTONS, // REPORT_COUNT (NUMBER_OF_BUTTONS) 0x55, 0x00, // UNIT_EXPONENT (0) 0x65, 0x00, // UNIT (None) 0x81, 0x02, // INPUT (Data,Var,Abs) /* Buttons END */ /* Buttons padding */ 0x75, 0x01, // REPORT_SIZE (1) 0x95, BUTTON_PADDING, // REPORT_COUNT (BUTTON_PADDING) 0x81, 0x03, // INPUT (Cnst,Var,Abs) /* Buttons padding END */ /* Encoder */ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x01, // USAGE (Pointer) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xFF, 0, // LOGICAL_MAXIMUM (512r) 0x75, 0x10, // REPORT_SIZE (16) 0x95, 0x01, // REPORT_COUNT (1) 0xa1, 0x00, // COLLECTION (Physical) 0x09, 0x30, // USAGE (X) 0x81, 0x02, // INPUT (Data,Var,Abs) 0xc0, // END_COLLECTION /* Encoder END*/ 0x85, 0x04, // REPORT_ID (4) /* LEDs begin */ 0x05, 0x0a, // USAGE_PAGE (Ordinals) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, NUMBER_OF_LEDS, // REPORT_COUNT (NUMBER_OF_LEDS) 0xa1, 0x02, // COLLECTION (Logical) 0x89, 0x04, // STRING_MINIMUM (4) 0x99, 0x0e, // STRING_MAXIMUM (14) 0x09, 0x01, // USAGE (Instance 1) 0x09, 0x02, // USAGE (Instance 2) 0x09, 0x03, // USAGE (Instance 3) 0x09, 0x04, // USAGE (Instance 4) 0x09, 0x05, // USAGE (Instance 5) 0x09, 0x06, // USAGE (Instance 6) 0x09, 0x07, // USAGE (Instance 7) 0x09, 0x08, // USAGE (Instance 8) 0x09, 0x09, // USAGE (Instance 9) 0x09, 0x0a, // USAGE (Instance 10) 0x09, 0x0b, // USAGE (Instance 11) 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0xc0, // END_COLLECTION /* LEDs END */ /* LEDs padding */ 0x75, 0x01, // REPORT_SIZE (1) 0x95, LED_PADDING, // REPORT_COUNT (BUTTON_PADDING) 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) /* LEDs padding END */ 0xc0 // END_COLLECTION }; static bool SendControl(uint8_t d) { return USB_SendControl(0, &d, 1) == 1; } static bool USB_SendStringDescriptor(const char *string_P, uint8_t string_len, uint8_t flags) { SendControl(2 + string_len * 2); SendControl(3); bool pgm = flags & TRANSFER_PGM; for (uint8_t i = 0; i < string_len; i++) { bool r = SendControl(pgm ? pgm_read_byte(&string_P[i]) : string_P[i]); r &= SendControl(0); // high byte if (!r) { return false; } } return true; } IIDXHID_::IIDXHID_() : PluggableUSBModule(1, 1, epType) { epType[0] = EP_TYPE_INTERRUPT_IN; //PluggableUSB().plug(this); } int IIDXHID_::getInterface(byte* interface_count) { *interface_count += 1; HIDDescriptor hid_interface = { D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE), D_HIDREPORT(sizeof(hid_report)), D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) }; return USB_SendControl(0, &hid_interface, sizeof(hid_interface)); } int IIDXHID_::getDescriptor(USBSetup& setup) { if (setup.wValueH == USB_DEVICE_DESCRIPTOR_TYPE) { return USB_SendControl(TRANSFER_PGM, (const uint8_t*)&USB_DeviceDescriptorIAD, sizeof(USB_DeviceDescriptorIAD)); } if (setup.wValueH == USB_STRING_DESCRIPTOR_TYPE) { if (setup.wValueL == IPRODUCT) { return USB_SendStringDescriptor(String_Product, strlen(String_Product), 0); } else if (setup.wValueL == IMANUFACTURER) { return USB_SendStringDescriptor(String_Manufacturer, strlen(String_Manufacturer), 0); } else if (setup.wValueL == ISERIAL) { return USB_SendStringDescriptor(String_Serial, strlen(String_Serial), 0); } else if (setup.wValueL >= STRING_ID_Base && setup.wValueL < (STRING_ID_Base + STRING_ID_Count)) { return USB_SendStringDescriptor(String_indiv[setup.wValueL - STRING_ID_Base], strlen(String_indiv[setup.wValueL - STRING_ID_Base]), 0); } } if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } if (setup.wIndex != pluggedInterface) { return 0; } return USB_SendControl(TRANSFER_PGM, hid_report, sizeof(hid_report)); } bool IIDXHID_::setup(USBSetup& setup) { if (pluggedInterface != setup.wIndex) { return false; } uint8_t request = setup.bRequest; uint8_t request_type = setup.bmRequestType; if (request_type == REQUEST_DEVICETOHOST_CLASS_INTERFACE) { return true; } if (request_type == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) { if (request == HID_SET_REPORT) { if (setup.wValueH == HID_REPORT_TYPE_OUTPUT) { USB_RecvControl(usb_data, setup.wLength); if (usb_data[0] == 4) { lamp_hid_state = usb_data[2] << 8 | usb_data[1]; lastHidUpdate = millis(); // No need to write lights or update lightmode here (for autoswitch), main loop() will take care of it } return true; } } } return false; } unsigned long IIDXHID_::getLastHidUpdate() { return lastHidUpdate; } void IIDXHID_::write_lights(uint32_t button_state, bool hid, bool reactive) { if (!reactive) { button_state = 0; } if (hid) { button_state |= lamp_hid_state; } for (int i = 0; i < NUMBER_OF_LEDS; i++) { digitalWrite(led_pins[i], ((button_state >> i) & 1)); } } int IIDXHID_::send_state(uint32_t button_state, int32_t turntable_state) { uint8_t data[6]; data[0] = (uint8_t) 5; data[1] = (uint8_t) (button_state >> 16) & 0xFF; /* HAT SWITCH */ data[2] = (uint8_t) (button_state & 0xFF); data[3] = (uint8_t) (button_state >> 8) & 0xFF; data[4] = (uint8_t) (turntable_state & 0xFF); data[5] = (uint8_t) (turntable_state >> 8) & 0xFF; return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, 6); }