250 lines
9.5 KiB
C++
250 lines
9.5 KiB
C++
#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);
|
|
}
|