diff --git a/include/Usb.h b/include/Usb.h new file mode 100644 index 000000000..39aab0d8b --- /dev/null +++ b/include/Usb.h @@ -0,0 +1,235 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#pragma once +#include "stdint.h" +#include "usbhid.h" +/* USB chapter 9 structures */ +#define _ch9_h_ + +// USB Device Classes +#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors +#define USB_CLASS_AUDIO 0x01 // Audio +#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control +#define USB_CLASS_HID 0x03 // HID +#define USB_CLASS_PHYSICAL 0x05 // Physical +#define USB_CLASS_IMAGE 0x06 // Image +#define USB_CLASS_PRINTER 0x07 // Printer +#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage +#define USB_CLASS_HUB 0x09 // Hub +#define USB_CLASS_CDC_DATA 0x0a // CDC-Data +#define USB_CLASS_SMART_CARD 0x0b // Smart-Card +#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security +#define USB_CLASS_VIDEO 0x0e // Video +#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare +#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device +#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller +#define USB_CLASS_MISC 0xef // Miscellaneous +#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific +#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific + +// Additional Error Codes +#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xD1 +#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2 +#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3 +#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4 +#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5 +#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6 +#define USB_ERROR_EPINFO_IS_NULL 0xD7 +#define USB_ERROR_INVALID_ARGUMENT 0xD8 +#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9 +#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA +#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB +#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET 0xE0 +#define USB_ERROR_FailGetDevDescr 0xE1 +#define USB_ERROR_FailSetDevTblEntry 0xE2 +#define USB_ERROR_FailGetConfDescr 0xE3 +#define USB_ERROR_TRANSFER_TIMEOUT 0xFF + +#define USB_XFER_TIMEOUT 5000 // (5000) USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec +//#define USB_NAK_LIMIT 32000 // NAK limit for a transfer. 0 means NAKs are not counted +#define USB_RETRY_LIMIT 3 // 3 retry limit for a transfer +#define USB_SETTLE_DELAY 200 // settle delay in milliseconds + +#define USB_NUMDEVICES 16 //number of USB devices +//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller +#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms + +/* USB state machine states */ +#define USB_STATE_MASK 0xf0 + +#define USB_STATE_DETACHED 0x10 +#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11 +#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12 +#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13 +#define USB_ATTACHED_SUBSTATE_SETTLE 0x20 +#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30 +#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40 +#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50 +#define USB_ATTACHED_SUBSTATE_WAIT_RESET 0x51 +#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60 +#define USB_STATE_ADDRESSING 0x70 +#define USB_STATE_CONFIGURING 0x80 +#define USB_STATE_RUNNING 0x90 +#define USB_STATE_ERROR 0xa0 + +/* Misc.USB constants */ +#define DEV_DESCR_LEN 18 //device descriptor length +#define CONF_DESCR_LEN 9 //configuration descriptor length +#define INTR_DESCR_LEN 9 //interface descriptor length +#define EP_DESCR_LEN 7 //endpoint descriptor length + +/* Standard Device Requests */ + +#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS +#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE +#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE +#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS +#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR +#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR +#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION +#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION +#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE +#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE +#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME + +#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up +#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode + +/* Setup Data Constants */ + +#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer +#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer +#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard +#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class +#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor +#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device +#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface +#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint +#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other + +/* USB descriptors */ + +#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor. +#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor. +#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor. +#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor. +#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor. +#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier. +#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration. +#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power. +#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor. + +#define HID_DESCRIPTOR_HID 0x21 + + + +/* OTG SET FEATURE Constants */ +#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP +#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP +#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP + +/* USB Endpoint Transfer Types */ +#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint. +#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint. +#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint. +#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint. +#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes + + +/* Standard Feature Selectors for CLEAR_FEATURE Requests */ +#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient +#define USB_FEATURE_TEST_MODE 2 // Device recipient + +/* descriptor data structures */ + +/* Device descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). + uint16_t bcdUSB; // USB Spec Release Number (BCD). + uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. + uint16_t idVendor; // Vendor ID (assigned by the USB-IF). + uint16_t idProduct; // Product ID (assigned by the manufacturer). + uint16_t bcdDevice; // Device release number (BCD). + uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. + uint8_t iProduct; // Index of String Descriptor describing the product. + uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. + uint8_t bNumConfigurations; // Number of possible configurations. +} __attribute__((packed)) USB_DEVICE_DESCRIPTOR; + +/* Configuration descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + uint16_t wTotalLength; // Total length of all descriptors for this configuration. + uint8_t bNumInterfaces; // Number of interfaces in this configuration. + uint8_t bConfigurationValue; // Value of this configuration (1 based). + uint8_t iConfiguration; // Index of String Descriptor describing the configuration. + uint8_t bmAttributes; // Configuration characteristics. + uint8_t bMaxPower; // Maximum power consumed by this configuration. +} __attribute__((packed)) USB_CONFIGURATION_DESCRIPTOR; + +/* Interface descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + uint8_t bInterfaceNumber; // Number of this interface (0 based). + uint8_t bAlternateSetting; // Value of this alternate interface setting. + uint8_t bNumEndpoints; // Number of endpoints in this interface. + uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t iInterface; // Index of String Descriptor describing the interface. +} __attribute__((packed)) USB_INTERFACE_DESCRIPTOR; + +/* Endpoint descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). + uint8_t bmAttributes; // Endpoint transfer type. + uint16_t wMaxPacketSize; // Maximum packet size. + uint8_t bInterval; // Polling interval in frames. +} __attribute__((packed)) USB_ENDPOINT_DESCRIPTOR; + +/* HID descriptor */ +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; // HID class specification release + uint8_t bCountryCode; + uint8_t bNumDescriptors; // Number of additional class specific descriptors + uint8_t bDescrType; // Type of class descriptor + uint16_t wDescriptorLength; // Total size of the Report descriptor +} __attribute__((packed)) USB_HID_DESCRIPTOR; + +typedef struct { + uint8_t bDescrType; // Type of class descriptor + uint16_t wDescriptorLength; // Total size of the Report descriptor +} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE; diff --git a/include/accel.h b/include/accel.h index 6f38ff806..e04010bff 100644 --- a/include/accel.h +++ b/include/accel.h @@ -13,6 +13,7 @@ extern "C" { #define LIS3DH_ADDRESS_2 0x19 #define LIS3DH_REG_CTRL1 0x20 #define LIS3DH_REG_CTRL4 0x23 +#define LIS3DH_REG_CTRL5 0x24 #define LIS3DH_REG_WHOAMI 0x0F #define LIS3DH_REG_OUT 0x28 | 0x80 // Set auto increment #define LIS3DH_REG_OUTADC1_L 0x08 | 0x80 @@ -22,13 +23,22 @@ extern "C" { #define LIS3DH_REG_OUTADC3_L 0x0C | 0x80 #define LIS3DH_REG_OUTADC3_H 0x0D | 0x80 #define LIS3DH_ID 0x33 +#define LIS3DSH_ID 0x3F +#define SC7A20_ID 0x11 #define LIS3DH_REG_TEMPCFG 0x1F #define MPU6050_ADDRESS 0x68 +#define MPU6050_ADDRESS_ALT 0x69 #define MPU6050_REG_ACCEL_OUT 0x3B #define MPU6050_REG_WHO_AM_I 0x75 #define MPU6050_REG_ACCEL_CONFIG 0x1C #define MPU6050_REG_PWR_MGMT_1 0x6B #define MPU6050_ID 0x68 +#define MPU6050_ID2 0x98 // Common register-compatible clone +#define MPU6050_ID3 0x70 // Register-compatible MPU-6500/clone ID +#define MPU6050_PWR1_SLEEP (1U << 6) +#define MPU6050_PWR1_CLKSEL_MASK 0x07 +#define MPU6050_PWR1_CLKSEL_XGYRO 0x01 +#define MPU6050_ACCEL_CONFIG_2G 0x00 void tick_accel(); #ifdef __cplusplus } diff --git a/include/ads1115.h b/include/ads1115.h new file mode 100644 index 000000000..8a0abe5dd --- /dev/null +++ b/include/ads1115.h @@ -0,0 +1,80 @@ +#pragma once + +#include "io.h" +#define ADS1115_ADDRESS_ADDR_GND 0x48 // address pin low (GND) +#define ADS1115_ADDRESS_ADDR_VDD 0x49 // address pin high (VCC) +#define ADS1115_ADDRESS_ADDR_SDA 0x4A // address pin tied to SDA pin +#define ADS1115_ADDRESS_ADDR_SCL 0x4B // address pin tied to SCL pin +#define ADS1115_RA_CONVERSION 0x00 +#define ADS1115_RA_CONFIG 0x01 +#define ADS1115_RA_LO_THRESH 0x02 +#define ADS1115_RA_HI_THRESH 0x03 + +#define ADS1115_CFG_OS_BIT 15 +#define ADS1115_CFG_MUX_BIT 14 +#define ADS1115_CFG_MUX_LENGTH 3 +#define ADS1115_CFG_PGA_BIT 11 +#define ADS1115_CFG_PGA_LENGTH 3 +#define ADS1115_CFG_MODE_BIT 8 +#define ADS1115_CFG_DR_BIT 7 +#define ADS1115_CFG_DR_LENGTH 3 +#define ADS1115_CFG_COMP_MODE_BIT 4 +#define ADS1115_CFG_COMP_POL_BIT 3 +#define ADS1115_CFG_COMP_LAT_BIT 2 +#define ADS1115_CFG_COMP_QUE_BIT 1 +#define ADS1115_CFG_COMP_QUE_LENGTH 2 + + +#define ADS1115_MUX_P0_N1 0x00 // default +#define ADS1115_MUX_P0_N3 0x01 +#define ADS1115_MUX_P1_N3 0x02 +#define ADS1115_MUX_P2_N3 0x03 +#define ADS1115_MUX_P0_NG 0x04 +#define ADS1115_MUX_P1_NG 0x05 +#define ADS1115_MUX_P2_NG 0x06 +#define ADS1115_MUX_P3_NG 0x07 + +#define ADS1115_PGA_6P144 0x00 +#define ADS1115_PGA_4P096 0x01 +#define ADS1115_PGA_2P048 0x02 // default +#define ADS1115_PGA_1P024 0x03 +#define ADS1115_PGA_0P512 0x04 +#define ADS1115_PGA_0P256 0x05 +#define ADS1115_PGA_0P256B 0x06 +#define ADS1115_PGA_0P256C 0x07 + +#define ADS1115_MV_6P144 0.187500 +#define ADS1115_MV_4P096 0.125000 +#define ADS1115_MV_2P048 0.062500 // default +#define ADS1115_MV_1P024 0.031250 +#define ADS1115_MV_0P512 0.015625 +#define ADS1115_MV_0P256 0.007813 +#define ADS1115_MV_0P256B 0.007813 +#define ADS1115_MV_0P256C 0.007813 + +#define ADS1115_MODE_CONTINUOUS 0x00 +#define ADS1115_MODE_SINGLESHOT 0x01 // default + +#define ADS1115_RATE_8 0x00 +#define ADS1115_RATE_16 0x01 +#define ADS1115_RATE_32 0x02 +#define ADS1115_RATE_64 0x03 +#define ADS1115_RATE_128 0x04 // default +#define ADS1115_RATE_250 0x05 +#define ADS1115_RATE_475 0x06 +#define ADS1115_RATE_860 0x07 + +#define ADS1115_COMP_MODE_HYSTERESIS 0x00 // default +#define ADS1115_COMP_MODE_WINDOW 0x01 + +#define ADS1115_COMP_POL_ACTIVE_LOW 0x00 // default +#define ADS1115_COMP_POL_ACTIVE_HIGH 0x01 + +#define ADS1115_COMP_LAT_NON_LATCHING 0x00 // default +#define ADS1115_COMP_LAT_LATCHING 0x01 + +#define ADS1115_COMP_QUE_ASSERT1 0x00 +#define ADS1115_COMP_QUE_ASSERT2 0x01 +#define ADS1115_COMP_QUE_ASSERT4 0x02 +#define ADS1115_COMP_QUE_DISABLE 0x03 // default +#define ADS1115_REG_RESET_VAL 0b1100001111100000 \ No newline at end of file diff --git a/include/btstack_config.h b/include/btstack_config.h index 3d1ee3576..fa6a3c113 100644 --- a/include/btstack_config.h +++ b/include/btstack_config.h @@ -1,19 +1,37 @@ -#pragma once +#ifndef _PICO_BTSTACK_BTSTACK_CONFIG_H +#define _PICO_BTSTACK_BTSTACK_CONFIG_H + +// Copy & paste from, with some custom changes: +// https://github.com/raspberrypi/pico-examples/blob/master/pico_w/bt/config/btstack_config.h // BTstack features that can be enabled #define ENABLE_LOG_INFO #define ENABLE_LOG_ERROR +#define ENABLE_LOG_DEBUG #define ENABLE_PRINTF_HEXDUMP #define ENABLE_SCO_OVER_HCI +#ifdef ENABLE_BLE +#define ENABLE_GATT_CLIENT_PAIRING +#define ENABLE_L2CAP_LE_CREDIT_BASED_FLOW_CONTROL_MODE +#define ENABLE_LE_CENTRAL +#define ENABLE_LE_DATA_LENGTH_EXTENSION +#define ENABLE_LE_PERIPHERAL +#define ENABLE_LE_PRIVACY_ADDRESS_RESOLUTION +#define ENABLE_LE_SECURE_CONNECTIONS +#else +#error "BP32: ENABLE_BLE should be defined" +#endif + #ifdef ENABLE_CLASSIC #define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE +#define ENABLE_GOEP_L2CAP +#else +#error "BP32: ENABLE_CLASSIC should be defined" #endif -#ifdef ENABLE_BLE -#define ENABLE_L2CAP_LE_CREDIT_BASED_FLOW_CONTROL_MODE -#define ENABLE_LE_PERIPHERAL -#define ENABLE_LE_CENTRAL +#if defined(ENABLE_CLASSIC) && defined(ENABLE_BLE) +#define ENABLE_CROSS_TRANSPORT_KEY_DERIVATION #endif // BTstack configuration. buffers, sizes, ... @@ -25,14 +43,14 @@ #define MAX_NR_AVRCP_CONNECTIONS 2 #define MAX_NR_BNEP_CHANNELS 1 #define MAX_NR_BNEP_SERVICES 1 -#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2 -#define MAX_NR_GATT_CLIENTS 1 -#define MAX_NR_HCI_CONNECTIONS 2 -#define MAX_NR_HID_HOST_CONNECTIONS 1 -#define MAX_NR_HIDS_CLIENTS 1 +#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2 +#define MAX_NR_GATT_CLIENTS 4 +#define MAX_NR_HCI_CONNECTIONS 4 +#define MAX_NR_HID_HOST_CONNECTIONS 4 +#define MAX_NR_HIDS_HOSTS 4 #define MAX_NR_HFP_CONNECTIONS 1 -#define MAX_NR_L2CAP_CHANNELS 4 -#define MAX_NR_L2CAP_SERVICES 3 +#define MAX_NR_L2CAP_CHANNELS 6 +#define MAX_NR_L2CAP_SERVICES 5 #define MAX_NR_RFCOMM_CHANNELS 1 #define MAX_NR_RFCOMM_MULTIPLEXERS 1 #define MAX_NR_RFCOMM_SERVICES 1 @@ -71,4 +89,9 @@ #define ENABLE_SOFTWARE_AES128 #define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS -#undef HAVE_BTSTACK_STDIN +#define HAVE_BTSTACK_STDIN + +// To get the audio demos working even with HCI dump at 115200, this truncates long ACL packets +// #define HCI_DUMP_STDOUT_MAX_SIZE_ACL 100 + +#endif // _PICO_BTSTACK_BTSTACK_CONFIG_H \ No newline at end of file diff --git a/include/commands.h b/include/commands.h index 7d1651474..a35119d6b 100644 --- a/include/commands.h +++ b/include/commands.h @@ -1,5 +1,6 @@ #include #include "midi_descriptors.h" +#include "reports/crkd.h" #ifdef __cplusplus extern "C" { #endif @@ -51,6 +52,11 @@ enum SerialCommands { COMMAND_ACCEL_VALID, COMMAND_READ_BLUETOOTH_INPUTS, COMMAND_WT_DRUM_VALID, + COMMAND_BH_DRUM_VALID, + COMMAND_READ_CRKD, + COMMAND_READ_MATRIX, + COMMAND_MUSTANG_NECK_VALID, + COMMAND_READ_PERIPHERAL_ENCODER, MAX=100 }; @@ -60,17 +66,21 @@ extern uint8_t lastSuccessfulTurntablePacketLeft[3]; extern uint8_t lastSuccessfulTurntablePacketRight[3]; extern uint8_t lastSuccessfulGH5Packet[2]; extern uint8_t lastSuccessfulClonePacket[4]; +extern crkd_neck_t lastCrkd; extern uint8_t wiiBytes; extern uint32_t lastWt[5]; extern uint8_t rawWt; extern uint8_t rawWtPeripheral; extern bool lastGH5WasSuccessful; extern bool lastCloneWasSuccessful; +extern bool lastCrkdWasSuccessful; extern bool lastTurntableWasSuccessfulLeft; extern bool lastTurntableWasSuccessfulRight; extern bool lastWiiWasSuccessful; extern bool lastPS2WasSuccessful; extern bool wt_drum_found; +extern bool bh_drum_found; +extern bool mustang_neck_found; extern uint16_t wiiControllerType; extern uint8_t ps2ControllerType; extern bool overrideR2; diff --git a/include/config.h b/include/config.h index ca995eb23..c7d07ab1b 100644 --- a/include/config.h +++ b/include/config.h @@ -13,6 +13,9 @@ extern "C" { // ConsoleType can change due to console detection extern uint8_t consoleType; +extern uint8_t arcadeSide; +extern uint8_t proGuitarType; +void setArcadeSide(uint8_t side); #ifdef CONFIGURABLE_BLOBS extern const uint8_t* config; extern const uint8_t* config_blobs; @@ -31,6 +34,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define DEVICE_TYPE_IS_KEYBOARD (DEVICE_TYPE == KEYBOARD_MOUSE_TYPE) #define DEVICE_TYPE_IS_GAMEPAD (!(DEVICE_TYPE_IS_KEYBOARD)) #define DEVICE_TYPE_IS_PRO (DEVICE_TYPE == ROCK_BAND_PRO_DRUM || DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_MUSTANG || DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_SQUIRE || DEVICE_TYPE == ROCK_BAND_PRO_KEYS) +#define DEVICE_TYPE_IS_PRO_GUITAR (DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_MUSTANG || DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_SQUIRE) #if DEVICE_TYPE == SKYLANDERS #define SUB_TYPE XINPUT_SKYLANDERS #define OG_XBOX_REPORT OGXboxGamepad_Data_t @@ -40,6 +44,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3SimpleGamepad_Data_t #define PS4_REPORT PS4Gamepad_Data_t +#define PS5_REPORT PS5Gamepad_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_FORCE_FEEDBACK #define PS3_FLAGS 0x07 #define HID_BUTTON_COUNT 14 @@ -69,6 +74,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3SimpleGamepad_Data_t #define PS4_REPORT PS4Gamepad_Data_t +#define PS5_REPORT PS5Gamepad_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_FORCE_FEEDBACK #define PS3_FLAGS 0x07 #define HID_BUTTON_COUNT 14 @@ -98,6 +104,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3SimpleGamepad_Data_t #define PS4_REPORT PS4Gamepad_Data_t +#define PS5_REPORT PS5Gamepad_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_FORCE_FEEDBACK #define PS3_FLAGS 0x07 #define HID_BUTTON_COUNT 14 @@ -127,6 +134,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3SimpleGamepad_Data_t #define PS4_REPORT PS4Gamepad_Data_t +#define PS5_REPORT PS5Gamepad_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_FORCE_FEEDBACK #define PS3_FLAGS 0x07 #define HID_BUTTON_COUNT 14 @@ -156,6 +164,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3SimpleGamepad_Data_t #define PS4_REPORT PS4Gamepad_Data_t +#define PS5_REPORT PS5Gamepad_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_FORCE_FEEDBACK #define PS3_FLAGS 0x07 #define HID_BUTTON_COUNT 14 @@ -185,6 +194,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3SimpleGamepad_Data_t #define PS4_REPORT PS4Gamepad_Data_t +#define PS5_REPORT PS5Gamepad_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_FORCE_FEEDBACK #define PS3_FLAGS 0x07 #define HID_BUTTON_COUNT 14 @@ -209,6 +219,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define SUB_TYPE XINPUT_GUITAR_ALTERNATE #define PS3_TYPE PS3_GH_GUITAR_PID #define PS4_TYPE PS4_GUITAR +#define PS4_EXTENDED PS4_FLAG_GUITAR_TILT | PS4_FLAG_GUITAR_WHAMMY #define WII_TYPE WII_RB_GUITAR_PID #define OG_XBOX_REPORT OGXboxGuitarHeroGuitar_Data_t #define XINPUT_REPORT XInputGuitarHeroGuitar_Data_t @@ -218,6 +229,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2GuitarHeroGuitar_Data_t #define PS3_REPORT PS3GuitarHeroGuitar_Data_t #define PS4_REPORT PS4RockBandGuitar_Data_t +#define PS5_REPORT PS5RockBandGuitar_Data_t // FFB flag enables support for the tap bar #define XINPUT_FLAGS XINPUT_FLAGS_FORCE_FEEDBACK #define PS3_FLAGS 0x06 @@ -241,6 +253,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define SUB_TYPE XINPUT_GUITAR #define PS3_TYPE PS3_RB_GUITAR_PID #define PS4_TYPE PS4_GUITAR +#define PS4_EXTENDED PS4_FLAG_GUITAR_TILT | PS4_FLAG_GUITAR_WHAMMY | PS4_FLAG_GUITAR_EFFECTS #define WII_TYPE WII_RB_GUITAR_PID #define OG_XBOX_REPORT OGXboxRockBandGuitar_Data_t #define XINPUT_REPORT XInputRockBandGuitar_Data_t @@ -250,6 +263,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2GuitarHeroGuitar_Data_t #define PS3_REPORT PS3RockBandGuitar_Data_t #define PS4_REPORT PS4RockBandGuitar_Data_t +#define PS5_REPORT PS5RockBandGuitar_Data_t // FFB flag was set on strats #define XINPUT_FLAGS XINPUT_FLAGS_FORCE_FEEDBACK #define PS3_FLAGS 0x06 @@ -281,6 +295,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3RockBandProGuitar_Data_t #define PS4_REPORT PS3RockBandProGuitar_Data_t +#define PS5_REPORT PS3RockBandProGuitar_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_NONE #define PS3_FLAGS 0x06 #define HID_BUTTON_COUNT 13 @@ -301,8 +316,8 @@ extern const uint8_t config[CONFIGURATION_LEN]; BTN_USAGE(BTN_THUMBR) #elif DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_SQUIRE #define SUB_TYPE XINPUT_PRO_GUITAR -#define PS3_TYPE PS3_SQUIRE_PID -#define WII_TYPE WII_SQUIRE_PID +#define PS3_TYPE PS3_SQUIRE_MPA_PID +#define WII_TYPE WII_SQUIRE_MPA_PID #define OG_XBOX_REPORT OGXboxGamepad_Data_t #define XINPUT_REPORT XInputRockBandProGuitar_Data_t #define XBOX_ONE_REPORT XboxOneRockBandProGuitar_Data_t @@ -311,6 +326,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3RockBandProGuitar_Data_t #define PS4_REPORT PS3RockBandProGuitar_Data_t +#define PS5_REPORT PS3RockBandProGuitar_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_NONE #define PS3_FLAGS 0x06 #define HID_BUTTON_COUNT 13 @@ -341,6 +357,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3RockBandProKeyboard_Data_t #define PS4_REPORT PS3RockBandProKeyboard_Data_t +#define PS5_REPORT PS3RockBandProKeyboard_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_NONE #define PS3_FLAGS 0x06 #define HID_BUTTON_COUNT 35 @@ -393,6 +410,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3GHLGuitar_Data_t #define PS4_REPORT PS4GHLGuitar_Data_t +#define PS5_REPORT PS5GHLGuitar_Data_t // GHL guitars set no navigation #define XINPUT_FLAGS XINPUT_FLAGS_NO_NAV #define PS3_FLAGS 0x06 @@ -417,15 +435,17 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define SUB_TYPE XINPUT_DRUMS #define PS3_TYPE PS3_GH_DRUM_PID #define PS4_TYPE PS4_DRUMS +#define PS4_EXTENDED 0x1f #define WII_TYPE WII_RB_DRUM_PID #define OG_XBOX_REPORT OGXboxGuitarHeroDrums_Data_t #define XINPUT_REPORT XInputGuitarHeroDrums_Data_t #define XBOX_ONE_REPORT XboxOneRockBandDrums_Data_t #define PC_REPORT PCGuitarHeroDrums_Data_t -#define PC_FESTIVAL_REPORT FestivalProGuitarLayerGH_Data_t +#define PC_FESTIVAL_REPORT FestivalProDrumsLayerGH_Data_t #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3GuitarHeroDrums_Data_t #define PS4_REPORT PS4RockBandDrums_Data_t +#define PS5_REPORT PS5RockBandDrums_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_NONE #define PS3_FLAGS 0x07 #define HID_BUTTON_COUNT 13 @@ -448,15 +468,17 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define SUB_TYPE XINPUT_DRUMS #define PS3_TYPE PS3_RB_DRUM_PID #define PS4_TYPE PS4_DRUMS +#define PS4_EXTENDED 0x1f #define WII_TYPE WII_RB_DRUM_PID #define OG_XBOX_REPORT OGXboxRockBandDrums_Data_t #define XINPUT_REPORT XInputRockBandDrums_Data_t #define XBOX_ONE_REPORT XboxOneRockBandDrums_Data_t -#define PC_FESTIVAL_REPORT FestivalProGuitarLayerRB_Data_t +#define PC_FESTIVAL_REPORT FestivalProDrumsLayerRB_Data_t #define PC_REPORT PCRockBandDrums_Data_t #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3RockBandDrums_Data_t #define PS4_REPORT PS4RockBandDrums_Data_t +#define PS5_REPORT PS5RockBandDrums_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_FORCE_FEEDBACK #define PS3_FLAGS 0x05 #define HID_BUTTON_COUNT 15 @@ -487,6 +509,7 @@ extern const uint8_t config[CONFIGURATION_LEN]; #define PS2_REPORT PS2Gamepad_Data_t #define PS3_REPORT PS3Turntable_Data_t #define PS4_REPORT PS3Turntable_Data_t +#define PS5_REPORT PS3Turntable_Data_t #define XINPUT_FLAGS XINPUT_FLAGS_NONE #define PS3_FLAGS 0x06 #define HID_BUTTON_COUNT 13 @@ -509,6 +532,12 @@ extern const uint8_t config[CONFIGURATION_LEN]; #ifndef PS4_TYPE #define PS4_TYPE PS4_GAMEPAD #endif +#ifndef PS4_EXTENDED +#define PS4_EXTENDED 0 +#endif +#ifndef PS5_TYPE +#define PS5_TYPE PS4_GAMEPAD +#endif #if DEVICE_TYPE_IS_GAMEPAD #ifndef HID_AXIS_COUNT #error missing HID_AXIS_COUNT and HID_BUTTON_COUNT @@ -527,31 +556,45 @@ extern const uint8_t config[CONFIGURATION_LEN]; #if DEVICE_TYPE_IS_GUITAR #define XBOX_ONE_VID XBOX_ONE_RB_VID #define XBOX_ONE_PID XBOX_ONE_RB_GUITAR_PID -#define XBOX_ONE_DESCRIPTOR_SIZE 256 +#define XBOX_ONE_DESCRIPTOR_SIZE 279 +#define PS4_VID PDP_VID +#define PS4_PID PS4_JAG_PID #elif DEVICE_TYPE_IS_DRUMS #define XBOX_ONE_VID XBOX_ONE_RB_VID #define XBOX_ONE_PID XBOX_ONE_RB_DRUM_PID -#define XBOX_ONE_DESCRIPTOR_SIZE 224 +#define XBOX_ONE_DESCRIPTOR_SIZE 237 +#define PS4_VID MADCATZ_VID +#define PS4_PID PS4_MADCATZ_DRUM_PID #elif DEVICE_TYPE == LIVE_GUITAR #define XBOX_ONE_VID XBOX_ONE_GHLIVE_DONGLE_VID #define XBOX_ONE_PID XBOX_ONE_GHLIVE_DONGLE_PID #define XBOX_ONE_DESCRIPTOR_SIZE 329 +#define PS4_VID XBOX_REDOCTANE_VID +#define PS4_PID PS4_GHLIVE_DONGLE_PID #elif DEVICE_TYPE == SKYLANDERS #define XBOX_ONE_VID XBOX_ONE_GHLIVE_DONGLE_VID #define XBOX_ONE_PID XBOX_ONE_GHLIVE_DONGLE_PID #define XBOX_ONE_DESCRIPTOR_SIZE 168 +#define PS4_VID 0x03EB +#define PS4_PID 0x2043 #elif DEVICE_TYPE == DISNEY_INFINITY #define XBOX_ONE_VID XBOX_ONE_GHLIVE_DONGLE_VID #define XBOX_ONE_PID XBOX_ONE_GHLIVE_DONGLE_PID #define XBOX_ONE_DESCRIPTOR_SIZE 96 +#define PS4_VID 0x03EB +#define PS4_PID 0x2043 #elif DEVICE_TYPE == LEGO_DIMENSIONS #define XBOX_ONE_VID XBOX_ONE_GHLIVE_DONGLE_VID #define XBOX_ONE_PID XBOX_ONE_GHLIVE_DONGLE_PID #define XBOX_ONE_DESCRIPTOR_SIZE 166 +#define PS4_VID 0x03EB +#define PS4_PID 0x2043 #else #define XBOX_ONE_VID XBOX_ONE_CONTROLLER_VID #define XBOX_ONE_PID XBOX_ONE_CONTROLLER_PID #define XBOX_ONE_DESCRIPTOR_SIZE 244 +#define PS4_VID 0x03EB +#define PS4_PID 0x2043 #endif typedef union { #if DEVICE_TYPE_IS_GAMEPAD diff --git a/include/controllers.h b/include/controllers.h index fffed4061..d643d0fa1 100644 --- a/include/controllers.h +++ b/include/controllers.h @@ -6,14 +6,8 @@ extern Xbox_One_State_t xbox_one_state; // State of the Xbox 360 controller init extern Xbox_360_State_t xbox_360_state; -extern uint16_t xbox_360_vid; -extern uint16_t xbox_360_pid; +extern long reset_after_360; -// Used for passing authentication data between the console and authentication controller -extern uint8_t data_from_console_size; -extern uint8_t data_from_controller_size; -extern uint8_t data_from_console[64]; -extern uint8_t data_from_controller[64]; // Sequence numbers used for sending reports to the xbox one extern uint8_t report_sequence_number; @@ -32,13 +26,17 @@ extern bool seen_ps4; // Used for detecting wii extern bool seen_hid_descriptor_read; +// Used for detecting og xbox +extern bool seen_og_xbox; + // Used for detecting pademu extern bool descriptor_requested; // Use for configuring commands that are pc specific extern bool seen_windows_xb1; extern bool seen_windows; -extern bool read_any_string; +extern bool seen_os_descriptor_read; +extern bool read_any_device_string; // Used for detecting any connection at all extern bool read_device_desc; diff --git a/include/defines.h b/include/defines.h index ac9683ad9..a562b13aa 100644 --- a/include/defines.h +++ b/include/defines.h @@ -8,11 +8,17 @@ #define ADXL345 1 #define LIS3DH 2 #define MPU6050 3 +#define SC7A20 4 +#define LIS3DSH 5 #define XINPUT_FLAGS_NO_NAV 0xFFFF #define XINPUT_FLAGS_NONE 0x0000 #define XINPUT_FLAGS_FORCE_FEEDBACK 0x000D +#define PS4_FLAG_GUITAR_EFFECTS 1 +#define PS4_FLAG_GUITAR_TILT 2 +#define PS4_FLAG_GUITAR_WHAMMY 4 + // https://docs.microsoft.com/en-us/windows/win32/xinput/xinput-and-controller-subtypes // http://forum.gimx.fr/viewtopic.php?f=11&t=2897&start=10 #define XINPUT_GAMEPAD 1 @@ -28,15 +34,13 @@ #define XINPUT_PRO_KEYS 15 #define XINPUT_ARCADE_PAD 19 #define XINPUT_TURNTABLE 23 -// Not real, but its easier for us to match this way -#define XINPUT_GUITAR_HERO_LIVE 24 #define XINPUT_PRO_GUITAR 25 -// Also not real, but nice for matching -#define XINPUT_GUITAR_WT 26 #define XINPUT_DISNEY_INFINITY_AND_LEGO_DIMENSIONS 33 +#define XINPUT_UDRAW 35 #define XINPUT_SKYLANDERS 36 -#define XINPUT_RB_DRUMS 37 -#define XINPUT_GH_DRUMS 38 +// Next few arent real, but its easier for us to match this way +#define XINPUT_GUITAR_HERO_LIVE 24 +#define XINPUT_GUITAR_WT 26 #define PS4_GAMEPAD 0 #define PS4_GUITAR 1 @@ -65,6 +69,7 @@ #define SKYLANDERS 22 #define LEGO_DIMENSIONS 23 #define TAIKO 24 +#define ARCADE 25 #define UNIVERSAL 0 #define XBOX360 1 @@ -99,6 +104,8 @@ #define PS2_ON_PS3 29 #define STADIA 30 #define XINPUTCOMPAT 31 +#define SWITCH2 32 +#define XINPUTCOMPAT_NEO_S 33 #define NON_CONTROLLER 0xFE #define UNKNOWN 0xFF @@ -147,6 +154,13 @@ #define BTN_END 0x0f #define BTN_USAGE(x) 0x09, x +#define DRUM_UNKNOWN 0 +#define DRUM_RB1 1 +#define DRUM_RB2 2 +#define DRUM_GH 3 +#define DRUM_ION 4 +#define GUITAR_CHECK 1 + typedef enum { WII_NUNCHUK = 0x0000, WII_CLASSIC_CONTROLLER = 0x0001, @@ -161,6 +175,7 @@ typedef enum { WII_NO_EXTENSION = 0x180b, WII_NOT_INITIALISED = 0xFFFF } WiiExtType_t; + typedef enum { Announce, WaitingDesc1, @@ -190,6 +205,7 @@ typedef enum { PSX_GUNCON, PSX_FLIGHTSTICK, PSX_MOUSE, + PSX_TAIKO, PSX_NO_DEVICE } PsxControllerType_t; @@ -222,4 +238,13 @@ typedef enum { #define RB_MIDI_NOTE_GREEN_CYMBAL 49 #define RB_MIDI_NOTE_YELLOW_CYMBAL 22 #define RB_MIDI_NOTE_BLUE_CYMBAL 51 -#define RB_MIDI_NOTE_KICK2 44 \ No newline at end of file +#define RB_MIDI_NOTE_KICK2 44 + +// Remap GH midi notes to RB counterparts +#define GH_REM_MIDI_NOTE_KICK RB_MIDI_NOTE_KICK +#define GH_REM_MIDI_NOTE_RED RB_MIDI_NOTE_RED +#define GH_REM_MIDI_NOTE_GREEN RB_MIDI_NOTE_GREEN +#define GH_REM_MIDI_NOTE_YELLOW RB_MIDI_NOTE_YELLOW_CYMBAL +#define GH_REM_MIDI_NOTE_BLUE RB_MIDI_NOTE_BLUE +#define GH_REM_MIDI_NOTE_ORANGE RB_MIDI_NOTE_BLUE_CYMBAL +#define GH_REM_MIDI_NOTE_KICK2 100 \ No newline at end of file diff --git a/include/descriptors.h b/include/descriptors.h index 6e2658941..06f3e0558 100644 --- a/include/descriptors.h +++ b/include/descriptors.h @@ -27,7 +27,6 @@ #define ENDPOINT_USAGE_FEEDBACK (1 << 4) #define ENDPOINT_USAGE_IMPLICIT_FEEDBACK (2 << 4) - typedef struct { USB_CONFIGURATION_DESCRIPTOR Config; USB_INTERFACE_DESCRIPTOR InterfaceGamepad; @@ -72,6 +71,18 @@ typedef struct { USB_ENDPOINT_DESCRIPTOR ReportOUTEndpoint12; } __attribute__((packed)) OG_XBOX_CONFIGURATION_DESCRIPTOR; +typedef struct { + USB_CONFIGURATION_DESCRIPTOR Config; + // uint8_t UnknownDescriptor1[3]; + USB_INTERFACE_DESCRIPTOR InterfaceHID; + USB_HID_DESCRIPTOR HIDDescriptor; + USB_ENDPOINT_DESCRIPTOR EndpointInHID; + USB_INTERFACE_DESCRIPTOR InterfaceVendor; + USB_ENDPOINT_DESCRIPTOR ReportINEndpoint21; + USB_ENDPOINT_DESCRIPTOR ReportOUTEndpoint22; + USB_ENDPOINT_DESCRIPTOR ReportINEndpoint23; +} __attribute__((packed)) GH_ARCADE_CONFIGURATION_DESCRIPTOR; + typedef struct { USB_CONFIGURATION_DESCRIPTOR Config; USB_INTERFACE_DESCRIPTOR InterfaceHID; diff --git a/include/endpoints.h b/include/endpoints.h index d3fdcea94..aaef3d01b 100644 --- a/include/endpoints.h +++ b/include/endpoints.h @@ -31,9 +31,12 @@ enum endpoints_t { #define HORI_POKKEN_TOURNAMENT_DX_PRO_PAD_PID 0x0092 #define NINTENDO_VID 0x057E #define SWITCH_PRO_PID 0x2009 +#define SWITCH_2_PRO_PID 0x2069 +#define SWITCH_2_GC_PID 0x2073 +#define SWITCH_2_JOY_R_PID 0x2066 +#define SWITCH_2_JOY_L_PID 0x2067 #define REDOCTANE_VID 0x12ba -#define PS4_VID 0x03EB -#define PS4_PID 0x2043 +#define REDOCTANE_GAMES_VID 0x3651 #define SONY_VID 0x054c #define SONY_DS3_PID 0x0268 #define PS4_DS_PID_1 0x05c4 @@ -41,19 +44,24 @@ enum endpoints_t { #define PS4_DS_PID_3 0x0ba0 #define PS4_STRAT_VID 0x0738 #define PS4_STRAT_PID 0x8261 +#define MADCATZ_VID 0x0738 #define PDP_VID 0x0E6F +#define CRKD_VID 0x0351 +#define CRKD_XB_MODE9 0x4161 #define PS4_JAG_PID 0x0173 #define PS4_RIFFMASTER_PID 0x024A +#define PS4_MADCATZ_DRUM_PID 0x8262 #define XBOX_ONE_RIFFMASTER_PID 0x0248 -#define PS5_DS_PID 0x0ce6 +#define PS5_DS_PID 0x0CE6 +#define PS5_DS_EDGE_PID 0x0DF2 #define PS5_RIFFMASTER_PID 0x0249 #define PS3_GH_GUITAR_PID 0x0100 #define PS3_GH_DRUM_PID 0x0120 #define PS3_RB_GUITAR_PID 0x0200 #define PS3_RB_DRUM_PID 0x0210 +#define PS3_MPA_DRUM_PID 0x0218 #define PS3_DJ_TURNTABLE_PID 0x0140 #define PS3_MUSTANG_PID 0x2430 -#define PS3_SQUIRE_PID 0x2530 #define PS3_MUSTANG_MPA_PID 0x2438 #define PS3_SQUIRE_MPA_PID 0x2538 #define PS3_DRUMS_PID 0x0210 @@ -62,15 +70,16 @@ enum endpoints_t { #define PS3WIIU_GHLIVE_DONGLE_PID 0x074b #define PS4_GHLIVE_DONGLE_PID 0x07BB #define HARMONIX_VID 0x1bad +#define XBOX_360_ION_ROCKER_VID 0x0130 #define WII_RB_GUITAR_PID 0x0004 #define WII_RB_GUITAR_2_PID 0x3010 #define WII_RB_DRUM_PID 0x0005 #define WII_RB_DRUM_2_PID 0x3110 #define WII_MUSTANG_PID 0x3430 -#define WII_SQUIRE_PID 0x3530 #define WII_MUSTANG_MPA_PID 0x3438 #define WII_SQUIRE_MPA_PID 0x3538 #define WII_DRUMS_PID 0x3130 +#define WII_MPA_DRUMS_PID 0x3138 #define WII_MPA_KEYBOARD_PID 0x3338 #define WII_KEYBOARD_PID 0x3330 #define MAD_CATZ_VID 0x0738 @@ -79,7 +88,8 @@ enum endpoints_t { #define XBOX_REDOCTANE_VID 0x1430 #define XBOX_POWERA_VID 0x24c6 #define XBOX_360_MUSTANG_PID 0x1430 -#define XBOX_360_SQUIRE_PID 0x1530 +#define XBOX_360_MUSTANG_MPA_PID 0x1438 +#define XBOX_360_SQUIRE_MPA_PID 0x1538 #define XBOX_ONE_GHLIVE_DONGLE_PID 0x079B #define XBOX_360_GHLIVE_DONGLE_PID 0x070B #define XBOX_360_WT_KIOSK_PID 0x4734 @@ -115,6 +125,9 @@ enum endpoints_t { #define STADIA_VID 0x18d1 #define STADIA_PID 0x9400 +#define PS3_UDRAW_VID 0x20D6 +#define PS3_UDRAW_PID 0xCB17 + #define SIMULTANEOUS_KEYS 6 diff --git a/include/gh5_neck.h b/include/gh5_neck.h new file mode 100644 index 000000000..96cead4cc --- /dev/null +++ b/include/gh5_neck.h @@ -0,0 +1 @@ +void tickGh5Neck(void); \ No newline at end of file diff --git a/include/hid.h b/include/hid.h index 988c7302b..d1c1fc8e9 100644 --- a/include/hid.h +++ b/include/hid.h @@ -77,11 +77,14 @@ extern const uint8_t keyboard_mouse_descriptor[NKRO_SIZE + SIXKRO_SIZE + CONSUMER_SIZE + MOUSE_SIZE]; extern const uint8_t ps3_descriptor[148]; extern const uint8_t ps3_instrument_descriptor[137]; +extern const uint8_t gha_descriptor[81]; extern const uint8_t ps4_descriptor[160]; +extern const uint8_t ps5_descriptor[165]; extern const uint8_t fnf_descriptor[53]; extern long last_strobe; extern uint8_t stage_kit_millis[5]; extern uint8_t strobe_delay; +extern uint8_t current_player; #if DEVICE_TYPE_IS_INSTRUMENT #if HID_BUTTON_PADDING extern const uint8_t pc_descriptor[90 + 2*HID_BUTTON_COUNT + 2*HID_AXIS_COUNT]; @@ -93,12 +96,14 @@ extern const uint8_t pc_descriptor[158]; #endif void handle_auth_led(void); void handle_player_leds(uint8_t player); +void reset_player_leds(void); void handle_rumble(uint8_t rumble_left, uint8_t rumble_right); void handle_keyboard_leds(uint8_t leds); void tick_leds(void); void hid_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_t report_id); uint8_t hid_get_report(uint8_t *data, uint8_t reqLen, uint8_t reportType, uint8_t report_id); -uint8_t handle_serial_command(uint8_t request, uint16_t wValue, uint8_t* response_buffer, bool* success); +uint16_t handle_serial_command(uint8_t request, uint16_t wValue, uint8_t* response_buffer, bool* success); #if BLUETOOTH_RX void bt_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_t report_id); +void send_player_leds_bt(void); #endif \ No newline at end of file diff --git a/include/io.h b/include/io.h index 0831cfc5f..4a07df0f9 100644 --- a/include/io.h +++ b/include/io.h @@ -27,11 +27,16 @@ bool twi_writeSingleToPointer(TWI_BLOCK, uint8_t address, uint8_t pointer, uint8 bool twi_writeToPointer(TWI_BLOCK, uint8_t address, uint8_t pointer, uint8_t length, uint8_t *data); void spi_begin(); +void uart_begin(); +bool read_uart(UART_BLOCK block, uint8_t header, uint8_t size, uint8_t *dest); + +void send_uart(UART_BLOCK block, uint8_t *data, uint8_t size); uint8_t spi_transfer(SPI_BLOCK block, uint8_t data); void spi_high(SPI_BLOCK block); void init_ack(); void init_att(); void go_to_sleep(); +void wakeup_360(); void read_serial(uint8_t* id, uint8_t len); extern volatile bool spi_acknowledged; #ifdef INPUT_WT_NECK diff --git a/include/midi.hpp b/include/midi.hpp new file mode 100644 index 000000000..a09a1f82d --- /dev/null +++ b/include/midi.hpp @@ -0,0 +1,51 @@ +#pragma once +#include +#include +#include "host/usbh.h" +#include "host/usbh_pvt.h" +#include "class/midi/midi.h" +#include "midi_descriptors.h" + +#define MIDI_CONTROL_COMMAND_MOD_WHEEL 1 +#define MIDI_CONTROL_COMMAND_SUSTAIN_PEDAL 64 +#define MIDI_CHANNEL_PROGUITAR_SQUIER 16 +#define MIDI_CHANNEL_PROGUITAR_MUSTANG 17 +#define MIDI_SYSEX_ID_PROGUITAR_SQUIER 0x08 +#define MIDI_SYSEX_ID_PROGUITAR_MUSTANG 0x0A +#define USB_PACKET_SIZE 4 + +typedef struct +{ + uint status; + uint pos; + uint actual_size; + uint8_t data[32]; + bool sysex_in_progress; +} cable_state_t; +class MidiDeviceWithChannel; +class MidiDevice +{ + +public: + MidiDevice(bool usbBased, Midi_Data_t* data); + virtual ~MidiDevice(); + void processMidiData(uint8_t *data, uint16_t len); + virtual void update(bool full_poll, bool send_events); + void rescan(bool first); + + // Endpoint stream + struct + { + tu_edpt_stream_t tx; + tu_edpt_stream_t rx; + + uint8_t rx_ff_buf[512]; + uint8_t tx_ff_buf[512]; + } ep_stream; + CFG_TUSB_MEM_ALIGN uint8_t m_ep_in_buf[TUH_EPSIZE_BULK_MAX]; + CFG_TUSB_MEM_ALIGN uint8_t m_ep_out_buf[TUH_EPSIZE_BULK_MAX]; + Midi_Data_t *midiData; + bool usbBased; + cable_state_t cable_status[16]; + uint8_t usb_pos = 0; +}; diff --git a/include/midi_descriptors.h b/include/midi_descriptors.h index 7bb845180..20c74bca5 100644 --- a/include/midi_descriptors.h +++ b/include/midi_descriptors.h @@ -338,11 +338,45 @@ typedef struct uint8_t Data3; /**< Third byte of data in the MIDI event. */ } __attribute__((packed)) MIDI_EVENT_PACKET; +typedef struct +{ + uint8_t header[5]; + uint8_t x : 1; // square + uint8_t a : 1; // cross + uint8_t b : 1; // circle + uint8_t y : 1; // triangle + + uint8_t : 1; // orange, l1 + uint8_t : 1; // tilt, r1 + uint8_t : 1; // l2 + uint8_t : 1; // r2 + + uint8_t back : 1; // select + uint8_t start : 1; + uint8_t : 1; + uint8_t : 1; + + uint8_t guide : 1; // ps + uint8_t capture : 1; // switch capture button + uint8_t : 2; + + uint8_t dpad : 4; + + uint8_t : 2; + uint8_t tilt : 1; + uint8_t : 1; + uint8_t end[2]; +} __attribute__((packed)) ProGuitar_Sysex_Buttons_t; typedef struct { uint8_t midiVelocitiesTemp[128]; uint8_t midiVelocities[128]; + uint8_t midiControlChanges[128]; int16_t midiPitchWheel; uint8_t midiModWheel; uint8_t midiSustainPedal; + bool seenProGuitar; + uint8_t midiFrets[6]; + uint8_t midiStringVelocities[6]; + ProGuitar_Sysex_Buttons_t proGuitarData; } __attribute__((packed)) Midi_Data_t; \ No newline at end of file diff --git a/include/mpr121.h b/include/mpr121.h index 16b42dfb0..28d812b54 100644 --- a/include/mpr121.h +++ b/include/mpr121.h @@ -1,6 +1,6 @@ #define MPR121_I2CADDR_DEFAULT 0x5A ///< default I2C address -#define MPR121_TOUCH_THRESHOLD_DEFAULT 5 ///< default touch threshold value -#define MPR121_RELEASE_THRESHOLD_DEFAULT 1 ///< default relese threshold value +#define MPR121_TOUCH_THRESHOLD_DEFAULT 14 ///< default touch threshold value +#define MPR121_RELEASE_THRESHOLD_DEFAULT 6 ///< default relese threshold value enum { MPR121_TOUCHSTATUS_L = 0x00, MPR121_TOUCHSTATUS_H = 0x01, diff --git a/include/pico_slave.h b/include/pico_slave.h index f6ffcf392..88ba50373 100644 --- a/include/pico_slave.h +++ b/include/pico_slave.h @@ -10,6 +10,8 @@ #define SLAVE_COMMAND_GET_WT 0x0B #define SLAVE_COMMAND_GET_WT_RAW 0x0C #define SLAVE_COMMAND_INITIALISE 0x0D +#define SLAVE_COMMAND_INIT_QUAD 0x0E +#define SLAVE_COMMAND_GET_QUAD 0x0F #define PIN_MODE_INPUT_PULLUP 0 #define PIN_MODE_INPUT 1 @@ -36,4 +38,5 @@ void slaveSetWtCounter(uint16_t counter); void slaveInitLED(uint8_t instance); void slaveWriteLED(uint8_t data); void slaveWriteAnalog(uint8_t pin, uint8_t val); +int32_t slaveReadQuad(); #endif \ No newline at end of file diff --git a/include/pin_funcs.h b/include/pin_funcs.h index 8272e4134..59dd38c36 100644 --- a/include/pin_funcs.h +++ b/include/pin_funcs.h @@ -11,6 +11,7 @@ uint16_t adc(uint8_t pin); uint8_t digital_read(uint8_t port, uint8_t mask); uint16_t adc_read(uint8_t pin, uint8_t mask); uint16_t multiplexer_read(uint8_t pin, uint32_t mask, uint32_t bits); +uint8_t matrix_read(uint8_t pin, uint8_t outPin); void digital_write(uint8_t port, uint8_t mask, uint8_t activeMask); void putWs2812(uint8_t r, uint8_t g, uint8_t b); void putWs2812(uint8_t r, uint8_t g, uint8_t b, uint8_t w); \ No newline at end of file diff --git a/include/protar_neck.h b/include/protar_neck.h new file mode 100644 index 000000000..055207155 --- /dev/null +++ b/include/protar_neck.h @@ -0,0 +1,2 @@ +#include "state_translation/pro_guitar.h" +protarneck_t tickMustangNeck(void); \ No newline at end of file diff --git a/include/reports/controller_reports.h b/include/reports/controller_reports.h index 94609872e..de28925e1 100644 --- a/include/reports/controller_reports.h +++ b/include/reports/controller_reports.h @@ -14,6 +14,7 @@ #include "reports/wii_reports.h" #include "reports/xbox_one_reports.h" #include "reports/xinput_reports.h" +#include "reports/crkd.h" #define STREAM_DECK_INPUT_REPORT_ID 1 #define STADIA_REPORT_ID 3 @@ -21,11 +22,13 @@ #define NKRO_KEYS ((0x73 / 8) + 1) #define SIMULTANEOUS_MIDI 12 #define KEYCODE_F24 115 -typedef struct { +typedef struct +{ // TMIDI_EventPacket_t midi[SIMULTANEOUS_MIDI]; } USB_MIDI_Data_t; -typedef struct { +typedef struct +{ uint8_t rid; bool left : 1; bool right : 1; @@ -36,7 +39,8 @@ typedef struct { int8_t scrollY; /** Current scroll Y delta movement on the mouse */ int8_t scrollX; /** Current scroll X delta movement on the mouse */ } __attribute__((packed)) USB_Mouse_Data_t; -typedef struct { +typedef struct +{ uint8_t rid; bool mediaNextTrack : 1; bool mediaPreviousTrack : 1; @@ -48,7 +52,8 @@ typedef struct { bool : 1; } USB_ConsumerControl_Data_t; -typedef struct { +typedef struct +{ uint8_t rid; bool leftCtrl : 1; bool leftShift : 1; @@ -58,8 +63,10 @@ typedef struct { bool rightShift : 1; bool rightAlt : 1; bool rWin : 1; - union { - struct { + union + { + struct + { uint8_t : 4; bool a : 1; bool b : 1; @@ -107,7 +114,7 @@ typedef struct { bool oemOpenBrackets : 1; bool oemCloseBrackets : 1; bool oemPipe : 1; - bool : 1; // Unused ansi pipe + bool : 1; // Unused ansi pipe bool oemSemicolon : 1; bool oemQuotes : 1; bool oemTilde : 1; @@ -145,7 +152,7 @@ typedef struct { bool multiply : 1; bool subtract : 1; bool add : 1; - bool : 1; // numpad enter + bool : 1; // numpad enter bool numPad1 : 1; bool numPad2 : 1; bool numPad3 : 1; @@ -180,7 +187,8 @@ typedef struct { }; } __attribute__((packed)) USB_NKRO_Data_t; -typedef struct { +typedef struct +{ uint8_t rid; bool leftCtrl : 1; bool leftShift : 1; @@ -195,7 +203,8 @@ typedef struct { keys. */ } __attribute__((packed)) USB_6KRO_Data_t; -typedef struct { +typedef struct +{ bool leftCtrl : 1; bool leftShift : 1; bool leftAlt : 1; @@ -209,7 +218,8 @@ typedef struct { keys. */ } __attribute__((packed)) USB_6KRO_Boot_Data_t; -typedef struct { +typedef struct +{ bool left : 1; bool right : 1; bool middle : 1; @@ -220,7 +230,8 @@ typedef struct { int8_t scrollX; /** Current scroll X delta movement on the mouse */ } __attribute__((packed)) USB_Mouse_Boot_Data_t; -typedef union { +typedef union +{ #ifdef TICK_SIXKRO USB_6KRO_Data_t keyboard; #else @@ -231,33 +242,36 @@ typedef union { USB_Mouse_Data_t mouse; } USB_Report_Data_t; -typedef union { - struct { - bool x : 1; // square - bool a : 1; // cross - bool b : 1; // circle - bool y : 1; // triangle +typedef union +{ + struct + { + bool x : 1; // square + bool a : 1; // cross + bool b : 1; // circle + bool y : 1; // triangle - bool leftShoulder : 1; // l1 - bool rightShoulder : 1; // r1 + bool leftShoulder : 1; // l1 + bool rightShoulder : 1; // r1 }; uint8_t val; } Buffer_Report_t; -typedef struct { - uint8_t x : 1; // square - uint8_t a : 1; // cross - uint8_t b : 1; // circle - uint8_t y : 1; // triangle - uint8_t leftShoulder : 1; // l1 - uint8_t rightShoulder : 1; // r1 - uint8_t back : 1; // select +typedef struct +{ + uint8_t x : 1; // square + uint8_t a : 1; // cross + uint8_t b : 1; // circle + uint8_t y : 1; // triangle + uint8_t leftShoulder : 1; // l1 + uint8_t rightShoulder : 1; // r1 + uint8_t back : 1; // select uint8_t start : 1; - uint8_t leftThumbClick : 1; // l3 - uint8_t rightThumbClick : 1; // r3 - uint8_t guide : 1; // ps - uint8_t capture : 1; // switch capture button + uint8_t leftThumbClick : 1; // l3 + uint8_t rightThumbClick : 1; // r3 + uint8_t guide : 1; // ps + uint8_t capture : 1; // switch capture button uint8_t leftBlue : 1; uint8_t leftRed : 1; uint8_t leftGreen : 1; @@ -281,8 +295,10 @@ typedef struct { uint8_t dpadLeft : 1; uint8_t dpadRight : 1; - union { - struct { + union + { + struct + { uint16_t genericButton1 : 1; uint16_t genericButton2 : 1; uint16_t genericButton3 : 1; @@ -305,7 +321,6 @@ typedef struct { uint16_t leftTrigger; uint16_t rightTrigger; - int16_t leftStickX; int16_t leftStickY; int16_t rightStickX; @@ -355,36 +370,35 @@ typedef struct { uint8_t highEFretVelocity; } __attribute__((packed)) USB_Host_Data_t; - - -typedef struct { +typedef struct +{ uint8_t report_id; // 0x03 uint8_t dpad : 4; uint8_t : 4; - + uint8_t capture : 1; uint8_t assistant : 1; - uint8_t r2 : 1; // r2 - uint8_t l2 : 1; // l2 - uint8_t guide : 1; // ps - uint8_t start : 1; // menu - uint8_t back : 1; // options - uint8_t rightThumbClick : 1; // r3 + uint8_t r2 : 1; // r2 + uint8_t l2 : 1; // l2 + uint8_t guide : 1; // ps + uint8_t start : 1; // menu + uint8_t back : 1; // options + uint8_t rightThumbClick : 1; // r3 - uint8_t leftThumbClick : 1; // l3 + uint8_t leftThumbClick : 1; // l3 uint8_t rightShoulder : 1; // r1 uint8_t leftShoulder : 1; // l1 - uint8_t y : 1; // triangle - uint8_t x : 1; // square - uint8_t b : 1; // circle - uint8_t a : 1; // cross + uint8_t y : 1; // triangle + uint8_t x : 1; // square + uint8_t b : 1; // circle + uint8_t a : 1; // cross uint8_t : 1; uint8_t leftStickX; uint8_t leftStickY; uint8_t rightStickX; uint8_t rightStickY; - uint8_t leftTrigger; // pressure_l2 - uint8_t rightTrigger; // pressure_r2 + uint8_t leftTrigger; // pressure_l2 + uint8_t rightTrigger; // pressure_r2 } __attribute__((packed)) Stadia_Data_t; \ No newline at end of file diff --git a/include/reports/crkd.h b/include/reports/crkd.h new file mode 100644 index 000000000..7ab61a93d --- /dev/null +++ b/include/reports/crkd.h @@ -0,0 +1,18 @@ +#pragma once +#include "stdint.h" +typedef struct +{ + uint8_t header; // {0xA5, 0x01};, though we are eating the first header byte + uint8_t len; // 0x0C; + uint8_t padding[2]; //{0x00, 0x00}; + uint8_t green : 1; + uint8_t red : 1; + uint8_t yellow : 1; + uint8_t blue : 1; + uint8_t orange : 1; + uint8_t : 3; + uint8_t dpadUpDown; // none: 0x80, up: 0x00, down: 0xFF + uint8_t dpadLeftRight; // none: 0x80, right: 0x00, left: 0xFF + uint8_t footer[3]; // {0x00, 0x01, 0x15}; + uint8_t crc; // CRC-8/MAXIM-DOW +} __attribute__((packed)) crkd_neck_t; \ No newline at end of file diff --git a/include/reports/pc_reports.h b/include/reports/pc_reports.h index c4e625545..95e3b9fc6 100644 --- a/include/reports/pc_reports.h +++ b/include/reports/pc_reports.h @@ -182,6 +182,36 @@ typedef struct uint8_t tilt; } __attribute__((packed)) PCGuitarHeroGuitar_Data_t; +typedef struct +{ + uint8_t always_1d; // Always 0x1d + uint8_t unk1; + uint8_t unk2; + uint8_t always_ff; // Always 0xFF + uint8_t tilt; + + union { + struct { + uint8_t dpadUp : 1; + uint8_t dpadDown : 1; + uint8_t dpadLeft : 1; + uint8_t dpadRight : 1; + uint8_t a : 1; // cross, green + uint8_t b : 1; // circle, red + uint8_t x : 1; // square, blue + uint8_t y : 1; // triangle, yellow + }; + struct { + uint8_t dpad : 4; + uint8_t : 4; + }; + }; + + uint8_t leftShoulder : 1; // orange, l1 + uint8_t : 3; + uint8_t side : 4; // 1 for left, 2 for right +} __attribute__((packed)) ArcadeGuitarHeroGuitar_Data_t; + // Festivals default mappings suck, so its easiest to set up custom mappings for that here typedef struct { @@ -253,6 +283,69 @@ typedef struct uint8_t slider; } __attribute__((packed)) FestivalProGuitarLayerRB_Data_t; +typedef struct +{ + uint8_t reportId; + uint8_t greenCymbal : 1; // a, cross, green + uint8_t green : 1; // b, circle, red + uint8_t blueCymbal : 1; // y, triangle, yellow + uint8_t blue : 1; // x, square, blue + + uint8_t kick2 : 1; // leftShoulder, orange, l1 + uint8_t kick : 1; // rightShoulder + uint8_t l2 : 1; // l2 + uint8_t r2 : 1; // r2 + uint8_t : 2; + uint8_t back : 1; // back, select + uint8_t start : 1; // start + + uint8_t guide : 1; // ps + uint8_t : 2; + + // To make things easier, we use bitfields here, and then we map to a proper hat later + union { + struct { + uint8_t yellowCymbal : 1; // dpadUp + uint8_t yellow : 1; // dpadDown + uint8_t red : 1; // dpadLeft + uint8_t dpadRight : 1; // dpadRight + uint8_t : 4; + }; + uint8_t dpad; + }; +} __attribute__((packed)) FestivalProDrumsLayerRB_Data_t; + +typedef struct +{ + uint8_t reportId; + uint8_t greenCymbal : 1; // a, cross, green + uint8_t green : 1; // b, circle, red + uint8_t blueCymbal : 1; // y, triangle, yellow + uint8_t blue : 1; // x, square, blue + + uint8_t kick2 : 1; // leftShoulder, orange, l1 + uint8_t kick : 1; // rightShoulder + uint8_t l2 : 1; // l2 + uint8_t r2 : 1; // r2 + uint8_t : 2; + uint8_t back : 1; // back, select + uint8_t start : 1; // start + + uint8_t guide : 1; // ps + uint8_t : 2; + + // To make things easier, we use bitfields here, and then we map to a proper hat later + union { + struct { + uint8_t yellowCymbal : 1; // dpadUp + uint8_t yellow : 1; // dpadDown + uint8_t red : 1; // dpadLeft + uint8_t dpadRight : 1; // dpadRight + uint8_t : 4; + }; + uint8_t dpad; + }; +} __attribute__((packed)) FestivalProDrumsLayerGH_Data_t; typedef struct { uint8_t reportId; @@ -281,7 +374,6 @@ typedef struct uint8_t pickup; uint8_t tilt; } __attribute__((packed)) PCRockBandGuitar_Data_t; - typedef struct { uint8_t reportId; @@ -431,12 +523,54 @@ typedef struct uint8_t pedalDigital : 1; uint8_t : 7; DPAD; - uint8_t key1; - uint8_t key2; - uint8_t key3; + union { + struct { + uint8_t key8 : 1; + uint8_t key7 : 1; + uint8_t key6 : 1; + uint8_t key5 : 1; + uint8_t key4 : 1; + uint8_t key3 : 1; + uint8_t key2 : 1; + uint8_t key1 : 1; + uint8_t key16 : 1; + uint8_t key15 : 1; + uint8_t key14 : 1; + uint8_t key13 : 1; + uint8_t key12 : 1; + uint8_t key11 : 1; + uint8_t key10 : 1; + uint8_t key9 : 1; + uint8_t key24 : 1; + uint8_t key23 : 1; + uint8_t key22 : 1; + uint8_t key21 : 1; + uint8_t key20 : 1; + uint8_t key19 : 1; + uint8_t key18 : 1; + uint8_t key17 : 1; + }; + uint8_t keys[3]; + }; + uint8_t pedalAnalog; uint8_t touchPad; - uint8_t velocities[5]; + union { + struct { + uint8_t velocity1 : 7; + uint8_t key25 : 1; + uint8_t velocity2 : 7; + uint8_t : 1; + uint8_t velocity3 : 7; + uint8_t : 1; + uint8_t velocity4 : 7; + uint8_t : 1; + uint8_t velocity5 : 7; + uint8_t : 1; + }; + + uint8_t velocities[5]; + }; } __attribute__((__packed__)) PCRockBandProKeyboard_Data_t; typedef struct { uint8_t reportTypeId; // 0x5B diff --git a/include/reports/ps3_reports.h b/include/reports/ps3_reports.h index 2804741e8..f17f05c9c 100644 --- a/include/reports/ps3_reports.h +++ b/include/reports/ps3_reports.h @@ -149,6 +149,60 @@ typedef struct { uint16_t accelZ; uint16_t gyro; } __attribute__((packed)) PS3Gamepad_Data_t; +typedef struct { + uint8_t reportId; + uint8_t : 8; + uint8_t back : 1; // select + uint8_t padFlag : 1; // left stick click, l3 + uint8_t cymbalFlag : 1; // right stick click, r3 + uint8_t start : 1; + + uint8_t dpadUp : 1; + uint8_t dpadRight : 1; + uint8_t dpadDown : 1; + uint8_t dpadLeft : 1; + + uint8_t l2 : 1; // l1 + uint8_t r2 : 1; // r1 + uint8_t leftShoulder : 1; // l1 + uint8_t rightShoulder : 1; // r1 + + uint8_t y : 1; // triangle + uint8_t b : 1; // circle + uint8_t a : 1; // cross + uint8_t x : 1; // square + + uint8_t guide : 1; + uint8_t : 7; + uint8_t : 8; + uint8_t leftStickX; + uint8_t leftStickY; + uint8_t rightStickX; + uint8_t rightStickY; + uint8_t padding_3[4]; + uint8_t pressureDpadUp; + uint8_t pressureDpadRight; + uint8_t pressureDpadDown; + uint8_t pressureDpadLeft; + uint8_t leftTrigger; // pressure_l2 + uint8_t rightTrigger; // pressure_r2 + uint8_t yellowVelocity; + uint8_t redVelocity; // If you hit two cymbals at once, it puts the velocity for the cymbal here + uint8_t greenVelocity; + uint8_t blueVelocity; + uint8_t blueCymbalVelocity; + uint8_t yellowCymbalVelocity; + uint8_t greenCymbalVelocity; + uint8_t orangeVelocity; + uint8_t kickVelocity; + uint8_t padding_4[12]; + // Each of the following are 10 bits in accuracy + // Centered/neutral state is nominally 0x0200, actual values may vary + uint16_t accelX; // Left/right acceleration (roll) + uint16_t accelZ; // Forward/back acceleration (pitch) + uint16_t accelY; // Up/down acceleration (gravity) + uint16_t gyro; // Left/right instantaneous rotation (yaw) +} __attribute__((packed)) PS3GamepadDrum_Data_t; typedef struct { uint8_t reportId; uint8_t : 8; @@ -253,6 +307,57 @@ typedef struct { uint16_t gyro; // Left/right instantaneous rotation (yaw) } __attribute__((packed)) PS3FestivalProGuitarLayer_Data_t; +typedef struct { + uint8_t reportId; + uint8_t : 8; + uint8_t back : 1; // select + uint8_t leftThumbClick : 1; // l3 + uint8_t rightThumbClick : 1; // r3 + uint8_t start : 1; + + uint8_t yellowCymbal : 1; // dpadUp + uint8_t dpadRight : 1; + uint8_t yellow : 1; + uint8_t red : 1; // dpadLeft + + uint8_t l2 : 1; // l2 - whammy + uint8_t r2 : 1; // r2 - overdrive + uint8_t kick2 : 1; // l1 (leftShoulder) - strum up + uint8_t kick : 1; // r1 (rightShoulder) - strum down + + uint8_t blue : 1; // triangle (y) - blue + uint8_t green : 1; // circle (b) - orange + uint8_t greenCymbal : 1; // cross (a) + uint8_t blueCymbal : 1; // square (x) - yellow + + uint8_t guide : 1; + uint8_t : 7; + uint8_t : 8; + uint8_t leftStickX; + uint8_t leftStickY; + uint8_t rightStickX; + uint8_t rightStickY; + uint8_t padding_3[4]; + uint8_t pressureDpadUp; + uint8_t pressureDpadRight; + uint8_t pressureDpadDown; + uint8_t pressureDpadLeft; + uint8_t leftTrigger; // pressure_l2 + uint8_t rightTrigger; // pressure_r2 + uint8_t pressureL1; + uint8_t pressureR1; + uint8_t pressureTriangle; + uint8_t pressureCircle; + uint8_t pressureCross; + uint8_t pressureSquare; + uint8_t padding_4[15]; + // Each of the following are 10 bits in accuracy + // Centered/neutral state is nominally 0x0200, actual values may vary + uint16_t accelX; // Left/right acceleration (roll) + uint16_t accelZ; // Forward/back acceleration (pitch) + uint16_t accelY; // Up/down acceleration (gravity) + uint16_t gyro; // Left/right instantaneous rotation (yaw) +} __attribute__((packed)) PS3FestivalProDrumLayer_Data_t; typedef struct { // Button bits uint8_t x : 1; // square @@ -411,7 +516,7 @@ typedef struct uint8_t unused1[8]; uint8_t yellowVelocity; - uint8_t redVelocity; // If you hit two cymbals at once, it puts the velocity for the cymbal here + uint8_t redVelocity; // If you hit two cymbals at once, it puts the velocity for the cymbal here uint8_t greenVelocity; uint8_t blueVelocity; uint8_t blueCymbalVelocity; @@ -456,18 +561,18 @@ typedef struct uint8_t yellowVelocity; uint8_t redVelocity; - uint8_t greenVelocity; + uint8_t greenVelocity; uint8_t blueVelocity; uint8_t kickVelocity; uint8_t orangeVelocity; uint8_t unused2[2]; - uint8_t midiByte1; // x + uint8_t midiByte1; // x uint8_t unused3; - uint16_t unused4; // z - uint8_t midiByte2; // y + uint16_t unused4; // z + uint8_t midiByte2; // y uint8_t unused7; - uint16_t unused6; // gyro + uint16_t unused6; // gyro } __attribute__((packed)) PS3GuitarHeroDrums_Data_t; typedef struct @@ -656,11 +761,52 @@ typedef struct uint8_t unused1[2]; - uint8_t key1; - uint8_t key2; - uint8_t key3; - - uint8_t velocities[5]; + union { + struct { + uint8_t key8 : 1; + uint8_t key7 : 1; + uint8_t key6 : 1; + uint8_t key5 : 1; + uint8_t key4 : 1; + uint8_t key3 : 1; + uint8_t key2 : 1; + uint8_t key1 : 1; + uint8_t key16 : 1; + uint8_t key15 : 1; + uint8_t key14 : 1; + uint8_t key13 : 1; + uint8_t key12 : 1; + uint8_t key11 : 1; + uint8_t key10 : 1; + uint8_t key9 : 1; + uint8_t key24 : 1; + uint8_t key23 : 1; + uint8_t key22 : 1; + uint8_t key21 : 1; + uint8_t key20 : 1; + uint8_t key19 : 1; + uint8_t key18 : 1; + uint8_t key17 : 1; + }; + uint8_t keys[3]; + }; + + union { + struct { + uint8_t velocity1 : 7; + uint8_t key25 : 1; + uint8_t velocity2 : 7; + uint8_t : 1; + uint8_t velocity3 : 7; + uint8_t : 1; + uint8_t velocity4 : 7; + uint8_t : 1; + uint8_t velocity5 : 7; + uint8_t : 1; + }; + + uint8_t velocities[5]; + }; uint8_t : 7; uint8_t overdrive : 1; @@ -775,3 +921,56 @@ typedef struct uint16_t unused4[3]; } __attribute__((packed)) PS3GHLGuitar_Data_t; + + +typedef struct +{ + uint8_t x : 1; // square, white1 + uint8_t a : 1; // cross, black1 + uint8_t b : 1; // circle, black2 + uint8_t y : 1; // triangle, black3 + + uint8_t leftShoulder : 1; // white2, l1 + uint8_t rightShoulder : 1; // white3, r1 + uint8_t : 1; + uint8_t : 1; + + uint8_t back : 1; // back, heroPower + uint8_t start : 1; // start, pause + uint8_t leftThumbClick : 1; // leftThumbClick, ghtv + uint8_t : 1; + + uint8_t guide : 1; // ps + uint8_t capture : 1; // switch capture button + uint8_t : 2; + + // To make things easier, we use bitfields here, and then we map to a proper hat later + uint8_t dpadUp : 1; + uint8_t dpadDown : 1; + uint8_t dpadLeft : 1; + uint8_t dpadRight : 1; + uint8_t : 4; + + uint8_t leftStickX; // leftStickX + uint8_t leftStickY; // leftStickY + uint8_t rightStickX; // rightStickX + uint8_t rightStickY; // rightStickY + + uint8_t unused3[4]; + uint8_t status; // 0x40 = pen touch, 0x80 = single finger, anything else = multi touch + uint8_t distance; // distance between fingers for multitouch (0x74 -> 0xff) + uint8_t pressure; // 0x74 -> 0xff, 0x60 if not pressed + uint8_t unused4; + uint8_t penXHigh; + uint8_t penYHigh; + uint8_t penXLow; + uint8_t penYLow; + + // Reminder that this value is 10-bit in range + // Each of the following are 10 bits in accuracy + // Centered/neutral state is nominally 0x0200, actual values may vary + uint16_t accelX; // Left/right acceleration (roll) + uint16_t accelZ; // Forward/back acceleration (pitch) + uint16_t accelY; // Up/down acceleration (gravity) + uint16_t gyro; // Left/right instantaneous rotation (yaw) +} __attribute__((packed)) PS3UDraw_Data_t; diff --git a/include/reports/ps4_reports.h b/include/reports/ps4_reports.h index 3911349ee..90859789e 100644 --- a/include/reports/ps4_reports.h +++ b/include/reports/ps4_reports.h @@ -154,11 +154,12 @@ typedef struct uint8_t soloBlue : 1; uint8_t soloOrange : 1; uint8_t : 3; - - uint8_t unused4[26]; - uint32_t crc32; + uint8_t unused4[16]; + // uint8_t unused4[26]; - bluetooth + // uint32_t crc32; } __attribute__((packed)) PS4RockBandGuitar_Data_t; + typedef struct { uint8_t reportId; @@ -207,8 +208,11 @@ typedef struct uint8_t blueCymbalVelocity; uint8_t greenCymbalVelocity; - uint8_t unused4[24]; - uint32_t crc32; + // uint8_t unused4[24]; + // uint32_t crc32; + uint8_t unused4[14]; + // uint8_t unused4[24]; - bluetooth + // uint32_t crc32; } __attribute__((packed)) PS4RockBandDrums_Data_t; typedef struct { @@ -216,8 +220,8 @@ typedef struct uint8_t unused1; uint8_t strumBar; - uint8_t whammy; uint8_t tilt; + uint8_t whammy; // To make things easier we use bitfields here and them map to dpad later uint8_t dpadUp : 1; diff --git a/include/reports/ps5_reports.h b/include/reports/ps5_reports.h index eb8523f21..62acbefb2 100644 --- a/include/reports/ps5_reports.h +++ b/include/reports/ps5_reports.h @@ -2,77 +2,152 @@ #include #define PS5_INPUT_REPORT_ID 1 -typedef struct { +typedef struct +{ + uint8_t counter : 7; + uint8_t unpressed : 1; + + // 12 bit X, followed by 12 bit Y + uint8_t data[3]; +} __attribute__((packed)) TouchpadXY; + +typedef struct +{ + TouchpadXY p1; + TouchpadXY p2; +} __attribute__((packed)) TouchpadData; + +typedef struct +{ + int16_t x; + int16_t y; + int16_t z; +} __attribute__((packed)) PSSensor; +typedef struct +{ uint8_t report_id; uint8_t leftStickX; uint8_t leftStickY; uint8_t rightStickX; uint8_t rightStickY; - uint8_t leftTrigger : 8; - uint8_t rightTrigger : 8; + uint8_t leftTrigger; + uint8_t rightTrigger; - uint8_t sequence_number; // 6 + uint8_t sequence_number; // 6 uint8_t dpad : 4; - uint8_t x : 1; // square - uint8_t a : 1; // cross - uint8_t b : 1; // circle - uint8_t y : 1; // triangle - - uint8_t leftShoulder : 1; // l1 - uint8_t rightShoulder : 1; // r1 - uint8_t l2 : 1; // l2 - uint8_t r2 : 1; // r2 - - - uint8_t back : 1; // share - uint8_t start : 1; // options - uint8_t leftThumbClick : 1; // l3 - uint8_t rightThumbClick : 1; // r3 + uint8_t x : 1; // square + uint8_t a : 1; // cross + uint8_t b : 1; // circle + uint8_t y : 1; // triangle + + uint8_t leftShoulder : 1; // l1 + uint8_t rightShoulder : 1; // r1 + uint8_t l2 : 1; // l2 + uint8_t r2 : 1; // r2 + + uint8_t back : 1; // share + uint8_t start : 1; // options + uint8_t leftThumbClick : 1; // l3 + uint8_t rightThumbClick : 1; // r3 uint8_t guide : 1; uint8_t touchpad : 1; + uint8_t : 6; + + uint8_t data_11; + + uint32_t auth_seq_number; + + PSSensor gyroscope; + PSSensor accelerometer; + + uint16_t data_28_29; + + uint16_t data_30_31_0x001a; + + TouchpadData touchpad_data; + + uint8_t data_40_55[16]; + + uint8_t hash[8]; + +} __attribute__((packed)) PS5Dpad_Data_t; +typedef struct +{ + uint8_t report_id; + uint8_t leftStickX; + uint8_t leftStickY; + uint8_t rightStickX; + uint8_t rightStickY; + uint8_t leftTrigger; + uint8_t rightTrigger; + + uint8_t sequence_number; // 6 + + uint8_t dpadUp : 1; + uint8_t dpadDown : 1; + uint8_t dpadLeft : 1; + uint8_t dpadRight : 1; + uint8_t x : 1; // square + uint8_t a : 1; // cross + uint8_t b : 1; // circle + uint8_t y : 1; // triangle + + uint8_t leftShoulder : 1; // l1 + uint8_t rightShoulder : 1; // r1 + uint8_t l2 : 1; // l2 + uint8_t r2 : 1; // r2 + + uint8_t back : 1; // share + uint8_t start : 1; // options + uint8_t leftThumbClick : 1; // l3 + uint8_t rightThumbClick : 1; // r3 + + uint8_t guide : 1; + uint8_t capture : 1; uint8_t mic : 1; - uint8_t dummy : 5; // 7-9 + uint8_t dummy : 5; // 7-9 } __attribute__((packed)) PS5Gamepad_Data_t; typedef struct { - uint8_t report_id; - uint8_t joystickX; - uint8_t joystickY; + uint8_t report_id; + uint8_t leftStickX; + uint8_t leftStickY; uint8_t unused1[5]; - // 0 - // 7 1 - // 6 8 2 - // 5 3 - // 4 - uint8_t dpad : 4; - uint8_t x : 1; // blue - uint8_t a : 1; // green - uint8_t b : 1; // red - uint8_t y : 1; // yellow + uint8_t dpadUp : 1; + uint8_t dpadDown : 1; + uint8_t dpadLeft : 1; + uint8_t dpadRight : 1; + uint8_t x : 1; // blue + uint8_t a : 1; // green + uint8_t b : 1; // red + uint8_t y : 1; // yellow - uint8_t leftShoulder : 1; // orange + uint8_t leftShoulder : 1; // orange uint8_t : 3; - uint8_t back : 1; // share - uint8_t start : 1; // options + + uint8_t back : 1; // share + uint8_t start : 1; // options uint8_t solo : 1; uint8_t p1 : 1; uint8_t guide : 1; - uint8_t : 7; + uint8_t capture : 1; // touchpad click + uint8_t : 6; uint8_t unused2; uint32_t packetCounter; - uint8_t unused3[25]; + uint8_t unused3[24]; + uint8_t pickup; uint8_t whammy; uint8_t tilt; @@ -96,4 +171,91 @@ typedef struct uint8_t unused4[11]; uint64_t checksum; -} __attribute__((__packed__)) PS5RockBandGuitar_Data_t; \ No newline at end of file +} __attribute__((__packed__)) PS5RockBandGuitar_Data_t; +typedef struct +{ + + uint8_t report_id; + uint8_t leftStickX; + uint8_t leftStickY; + + uint8_t unused1[5]; + + uint8_t dpadUp : 1; + uint8_t dpadDown : 1; + uint8_t dpadLeft : 1; + uint8_t dpadRight : 1; + uint8_t x : 1; // blue + uint8_t a : 1; // green + uint8_t b : 1; // red + uint8_t y : 1; // yellow + + uint8_t leftShoulder : 1; // orange + uint8_t rightShoulder : 1; // orange + uint8_t : 2; + uint8_t back : 1; // share + uint8_t start : 1; // options + uint8_t : 2; + + uint8_t guide : 1; + uint8_t capture : 1; // touchpad click + uint8_t : 6; + + uint8_t unused2; + + uint32_t packetCounter; + + uint8_t unused3[24]; + + uint8_t redVelocity; + uint8_t blueVelocity; + uint8_t yellowVelocity; + uint8_t greenVelocity; + + uint8_t yellowCymbalVelocity; + uint8_t blueCymbalVelocity; + uint8_t greenCymbalVelocity; + uint8_t unused4[9]; + uint64_t checksum; +} __attribute__((__packed__)) PS5RockBandDrums_Data_t; + +typedef struct +{ + + uint8_t report_id; + + uint8_t leftStickX; + uint8_t strumBar; + uint8_t whammy; + uint8_t tilt; + + uint8_t unused1[2]; + + uint8_t dpadUp : 1; + uint8_t dpadDown : 1; + uint8_t dpadLeft : 1; + uint8_t dpadRight : 1; + uint8_t x : 1; // blue + uint8_t a : 1; // green + uint8_t b : 1; // red + uint8_t y : 1; // yellow + + uint8_t leftShoulder : 1; // orange + uint8_t rightShoulder : 1; // orange + uint8_t : 2; + uint8_t back : 1; // share + uint8_t start : 1; // options + uint8_t leftThumbClick : 1; + uint8_t p1 : 1; + + uint8_t guide : 1; + uint8_t capture : 1; // touchpad click + uint8_t : 6; + + uint8_t unused2; + + uint32_t packetCounter; + + uint8_t unused3[40]; + uint64_t checksum; +} __attribute__((__packed__)) PS5GHLGuitar_Data_t; \ No newline at end of file diff --git a/include/reports/switch_reports.h b/include/reports/switch_reports.h index 82006c6b6..24e967c0b 100644 --- a/include/reports/switch_reports.h +++ b/include/reports/switch_reports.h @@ -1,20 +1,106 @@ #pragma once #include #define SWITCH_PRO_CON_FULL_REPORT_ID 0x30 -typedef struct { +#define SWITCH_2_GC_FULL_REPORT_ID 0x0A +#define SWITCH_2_PRO_CON_FULL_REPORT_ID 0x09 +#define SWITCH_2_STICK_CENTER 2048 +typedef struct +{ int16_t accX, accY, accZ; int16_t gyroX, gyroY, gyroZ; } __attribute__((packed)) ImuData; +typedef struct +{ + uint8_t reportId; // 0x0A + uint8_t packetId; // counts up for each packet + uint8_t status; // 0x20 + uint8_t b : 1; + uint8_t a : 1; + uint8_t y : 1; + uint8_t x : 1; + uint8_t r2 : 1; + uint8_t rightShoulder : 1; + uint8_t start : 1; + uint8_t rightThumbClick: 1; + + uint8_t dpadDown : 1; + uint8_t dpadRight : 1; + uint8_t dpadLeft : 1; + uint8_t dpadUp : 1; + uint8_t l2 : 1; + uint8_t leftShoulder : 1; + uint8_t back : 1; + uint8_t leftThumbClick: 1; + + uint8_t guide : 1; + uint8_t capture : 1; + uint8_t gl : 1; + uint8_t gr : 1; + uint8_t c : 1; + uint8_t : 3; + + uint16_t leftStickX : 12; + uint16_t leftStickY : 12; + uint16_t rightStickX : 12; + uint16_t rightStickY : 12; + uint8_t vibrationCode; + uint8_t leftTrigger; + uint8_t rightTrigger; + uint8_t imuLength; + uint8_t motionBuffer[10]; +} __attribute__((packed)) Switch2ProGamepadGC_Data_t; + +typedef struct +{ + uint8_t reportId; // 0x09 + uint8_t packetId; // counts up for each packet + uint8_t status; // 0x20 + uint8_t b : 1; + uint8_t a : 1; + uint8_t y : 1; + uint8_t x : 1; + uint8_t rightShoulder : 1; + uint8_t r2 : 1; + uint8_t start : 1; + uint8_t rightThumbClick: 1; + + uint8_t dpadDown : 1; + uint8_t dpadRight : 1; + uint8_t dpadLeft : 1; + uint8_t dpadUp : 1; + uint8_t leftShoulder : 1; + uint8_t l2 : 1; + uint8_t back : 1; + uint8_t leftThumbClick: 1; + + uint8_t guide : 1; + uint8_t capture : 1; + uint8_t gl : 1; + uint8_t gr : 1; + uint8_t c : 1; + uint8_t : 3; + + uint16_t leftStickX : 12; + uint16_t leftStickY : 12; + uint16_t rightStickX : 12; + uint16_t rightStickY : 12; + uint8_t vibrationCode; + uint8_t leftTrigger; + uint8_t rightTrigger; + uint8_t imuLength; + uint8_t motionBuffer[10]; +} __attribute__((packed)) Switch2ProGamepad_Data_t; + typedef struct { - uint8_t connection_info : 4; - uint8_t battery_level : 4; + uint8_t reportId; // 0x0A + uint8_t packetId; // counts up for each packet + uint8_t status; // 0x80 uint8_t y : 1; uint8_t x : 1; uint8_t b : 1; uint8_t a : 1; - uint8_t dummy1 : 2; uint8_t rightShoulder : 1; uint8_t rightTrigger : 1; @@ -23,50 +109,46 @@ typedef struct { uint8_t start : 1; // plus uint8_t leftThumbClick : 1; // l3 uint8_t rightThumbClick : 1; // r3 - uint8_t guide : 1; // home uint8_t capture : 1; uint8_t dummy2 : 2; - uint8_t dpad : 4; + uint8_t dpadDown : 1; + uint8_t dpadUp : 1; + uint8_t dpadRight : 1; + uint8_t dpadLeft : 1; uint8_t dummy3 : 2; uint8_t leftShoulder : 1; uint8_t leftTrigger : 1; // Bytes 6-11 - uint8_t leftStickX; - uint8_t leftStickY; - uint8_t rightStickX; - uint8_t rightStickY; - - uint8_t vibratorInput; // What is this used for? - - // Bytes 13-48 - // Three samples of the IMU is sent in one message - // See: https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/imu_sensor_notes.md - ImuData imu[3]; + uint16_t leftStickX : 12; + uint16_t leftStickY : 12; + uint16_t rightStickX : 12; + uint16_t rightStickY : 12; } __attribute__((packed)) SwitchProGamepad_Data_t; -typedef struct { +typedef struct +{ // Button bits uint8_t y : 1; uint8_t b : 1; uint8_t a : 1; uint8_t x : 1; - uint8_t leftShoulder : 1; // l1 - uint8_t rightShoulder : 1; // r1 - uint8_t l2 : 1; // l2 - uint8_t r2 : 1; // r2 + uint8_t leftShoulder : 1; // l1 + uint8_t rightShoulder : 1; // r1 + uint8_t l2 : 1; // l2 + uint8_t r2 : 1; // r2 - uint8_t back : 1; // select + uint8_t back : 1; // select uint8_t start : 1; - uint8_t leftThumbClick : 1; // l3 - uint8_t rightThumbClick : 1; // r3 + uint8_t leftThumbClick : 1; // l3 + uint8_t rightThumbClick : 1; // r3 - uint8_t guide : 1; // ps - uint8_t capture : 1; // switch capture button + uint8_t guide : 1; // ps + uint8_t capture : 1; // switch capture button uint8_t : 2; // To make things easier, we use bitfields here, and then we map to a proper hat later @@ -94,29 +176,79 @@ typedef struct { // Festivals default mappings suck, so its easiest to set up custom mappings for that here typedef struct { - uint8_t y : 1; // y, triangle, yellow - uint8_t rightShoulder : 1; // b, circle, red + // Button bits + uint8_t x : 1; + uint8_t b : 1; + uint8_t a : 1; + uint8_t y : 1; + + uint8_t leftShoulder : 1; // l1 + uint8_t rightShoulder : 1; // r1 + uint8_t l2 : 1; // l2 + uint8_t r2 : 1; // r2 + + uint8_t back : 1; // select + uint8_t start : 1; + uint8_t solo : 1; // l3 + uint8_t rightThumbClick : 1; // r3 + + uint8_t guide : 1; // ps + uint8_t capture : 1; // switch capture button + uint8_t : 2; + + // To make things easier, we use bitfields here, and then we map to a proper hat later + uint8_t dpadUp : 1; + uint8_t dpadDown : 1; + uint8_t dpadLeft : 1; + uint8_t dpadRight : 1; + uint8_t : 4; + + // Stick axes + // Neutral state is 0x80 + // X axis is left at 0x00, right at 0xFF + // Y axis is top at 0x00, bottom at 0xFF + uint8_t slider; + uint8_t pickup; + uint8_t whammy; + uint8_t unused; + + uint8_t unused2[12]; + uint16_t tilt; // accelX + uint16_t accelZ; + uint16_t accelY; + uint16_t unused3; +} __attribute__((packed)) SwitchFestivalGuitar_Data_t; + +// Festivals default mappings suck, so its easiest to set up custom mappings for that here +typedef struct +{ + uint8_t y : 1; // y, triangle, yellow + uint8_t rightShoulder : 1; // b, circle, red uint8_t leftShoulder : 1; // a, cross, green - uint8_t x : 1; // x, square, blue + uint8_t x : 1; // x, square, blue - uint8_t dpadUp : 1; // leftShoulder, orange, l1 - uint8_t dpadDown : 1; // rightShoulder, spPedal, r1 - uint8_t back: 1; // back, select - uint8_t start : 1; // start + uint8_t dpadUp : 1; // leftShoulder, orange, l1 + uint8_t dpadDown : 1; // rightShoulder, spPedal, r1 + uint8_t whammy : 1; // l2 + uint8_t tilt : 1; // r2 - uint8_t guide : 1; // ps + uint8_t back : 1; // back, select + uint8_t start : 1; // start uint8_t : 2; - uint8_t whammy : 1; - uint8_t tilt : 1; + + uint8_t guide : 1; // ps uint8_t : 2; + // To make things easier, we use bitfields here, and then we map to a proper hat later - union { - struct { - uint8_t b : 1; // dpadUp - uint8_t dpadRight : 1; // dpadDown - uint8_t a : 1; // dpadLeft - uint8_t dpadLeft : 1; // dpadRight + union + { + struct + { + uint8_t b : 1; // dpadUp + uint8_t dpadRight : 1; // dpadDown + uint8_t a : 1; // dpadLeft + uint8_t dpadLeft : 1; // dpadRight uint8_t : 4; }; uint8_t dpad; @@ -126,8 +258,44 @@ typedef struct uint8_t slider; } __attribute__((packed)) SwitchFestivalProGuitarLayer_Data_t; +// Festivals default mappings suck, so its easiest to set up custom mappings for that here +typedef struct +{ + uint8_t blue : 1; // y, triangle, yellow + uint8_t green : 1; // b, circle, red + uint8_t greenCymbal : 1; // a, cross, green + uint8_t blueCymbal : 1; // x, square, blue -typedef struct { + uint8_t kick2 : 1; // leftShoulder, orange, l1 + uint8_t kick : 1; // rightShoulder, spPedal, r1 + uint8_t l2 : 1; // l2 + uint8_t r2 : 1; // r2 + + uint8_t back : 1; // back, select + uint8_t start : 1; // start + uint8_t : 2; + + uint8_t guide : 1; // ps + uint8_t : 2; + + + // To make things easier, we use bitfields here, and then we map to a proper hat later + union + { + struct + { + uint8_t yellowCymbal : 1; // dpadUp + uint8_t yellow : 1; // dpadDown + uint8_t red : 1; // dpadLeft + uint8_t dpadRight : 1; // dpadRight + uint8_t : 4; + }; + uint8_t dpad; + }; +} __attribute__((packed)) SwitchFestivalProDrumsLayer_Data_t; + +typedef struct +{ uint8_t y : 1; uint8_t b : 1; uint8_t a : 1; @@ -139,8 +307,8 @@ typedef struct { uint8_t back : 1; uint8_t start : 1; - uint8_t leftThumbClick : 1; //l3 centerLeft - uint8_t rightThumbClick : 1; //r3 centerRight + uint8_t leftThumbClick : 1; // l3 centerLeft + uint8_t rightThumbClick : 1; // r3 centerRight uint8_t guide : 1; uint8_t capture : 1; uint8_t : 2; diff --git a/include/reports/xbox_one_reports.h b/include/reports/xbox_one_reports.h index a0d73e1bb..b7bafe98d 100644 --- a/include/reports/xbox_one_reports.h +++ b/include/reports/xbox_one_reports.h @@ -139,6 +139,10 @@ typedef struct uint8_t : 3; uint8_t unknown[3]; + int16_t joystickX; + int16_t joystickY; + + uint8_t consoleFunctions[14]; } __attribute__((packed)) XboxOneRockBandGuitar_Data_t; typedef struct diff --git a/include/reports/xinput_reports.h b/include/reports/xinput_reports.h index 4487f4d85..d1ac8a19a 100644 --- a/include/reports/xinput_reports.h +++ b/include/reports/xinput_reports.h @@ -26,13 +26,15 @@ #define BB_BLUE 0 #define BB_YELLOW 0 -typedef struct { +typedef struct +{ uint8_t rid; uint8_t rsize; uint8_t led; } __attribute__((packed)) XInputLEDReport_t; -typedef struct { +typedef struct +{ uint8_t rid; uint8_t rsize; uint8_t unused; @@ -41,7 +43,8 @@ typedef struct { uint8_t unused2[3]; } __attribute__((packed)) XInputRumbleReport_t; -typedef struct { +typedef struct +{ uint8_t rid; uint8_t rsize; uint8_t padding; @@ -50,7 +53,8 @@ typedef struct { uint8_t padding_2[3]; } __attribute__((packed)) XInputVibrationCapabilities_t; -typedef struct { +typedef struct +{ uint8_t rid; uint8_t rsize; uint16_t buttons; @@ -64,11 +68,13 @@ typedef struct { uint16_t flags; } __attribute__((packed)) XInputInputCapabilities_t; -typedef struct { +typedef struct +{ uint32_t serial; } __attribute__((packed)) XInputSerialNumber_t; -typedef struct { +typedef struct +{ uint8_t rid; uint8_t rsize; uint8_t controllerNumber; @@ -94,7 +100,8 @@ typedef struct { uint8_t reserved; } __attribute__((packed)) XInputBigButton_Data_t; -typedef struct { +typedef struct +{ uint8_t rid; uint8_t rsize; uint8_t dpadUp : 1; @@ -124,9 +131,52 @@ typedef struct { int16_t rightStickX; int16_t rightStickY; uint8_t reserved_1[6]; + } __attribute__((packed)) XInputGamepad_Data_t; +// 0x01 +// 0x02 +// 0x08 +// 0x10 +// 0x40 +// 0x80 +typedef struct +{ + uint8_t rid; + uint16_t leftStickX; + uint16_t leftStickY; + uint16_t rightStickX; + uint16_t rightStickY; + uint16_t leftTrigger; + uint16_t rightTrigger; + + uint8_t dpad : 4; + uint8_t : 4; + + uint8_t a : 1; + uint8_t b : 1; + uint8_t : 1; + uint8_t x : 1; + + uint8_t y : 1; + uint8_t :1; + uint8_t leftShoulder : 1; + uint8_t rightShoulder : 1; + + uint8_t :1; + uint8_t :1; + uint8_t back : 1; + uint8_t start : 1; + + uint8_t guide:1; + uint8_t leftThumbClick : 1; + uint8_t rightThumbClick : 1; + uint8_t : 1; -typedef struct { + uint8_t capture : 1; + uint8_t : 3; +} __attribute__((packed)) XInputCompatGamepad_Data_t; +typedef struct +{ uint8_t rid; uint16_t leftStickX; uint16_t leftStickY; @@ -150,9 +200,10 @@ typedef struct { uint8_t leftThumbClick : 1; uint8_t rightThumbClick : 1; uint8_t : 6; -} __attribute__((packed)) XInputCompatGamepad_Data_t; +} __attribute__((packed)) XInputCompatGamepad2_Data_t; -typedef struct { +typedef struct +{ uint8_t rid; uint8_t guide : 1; uint8_t : 7; @@ -168,24 +219,24 @@ typedef struct uint8_t start : 1; uint8_t back : 1; - uint8_t leftThumbClick : 1; // pedal2 - uint8_t padFlag : 1; // right thumb click + uint8_t leftThumbClick : 1; // pedal2 + uint8_t padFlag : 1; // right thumb click - uint8_t leftShoulder : 1; // pedal1 - uint8_t cymbalFlag : 1; // right shoulder click + uint8_t leftShoulder : 1; // pedal1 + uint8_t cymbalFlag : 1; // right shoulder click uint8_t guide : 1; uint8_t : 1; - uint8_t a : 1; // green - uint8_t b : 1; // red - uint8_t x : 1; // blue - uint8_t y : 1; // yellow + uint8_t a : 1; // green + uint8_t b : 1; // red + uint8_t x : 1; // blue + uint8_t y : 1; // yellow - uint8_t unused[2]; - int16_t redVelocity; - int16_t yellowVelocity; - int16_t blueVelocity; - int16_t greenVelocity; + uint8_t unused[2]; // trigger + int16_t redVelocity; // lx + int16_t yellowVelocity; // ly + int16_t blueVelocity; // rx + int16_t greenVelocity; // ry uint8_t reserved_1[6]; } __attribute__((packed)) XInputRockBandDrums_Data_t; @@ -200,18 +251,18 @@ typedef struct uint8_t start : 1; uint8_t back : 1; - uint8_t leftThumbClick : 1; // isGuitarHero + uint8_t leftThumbClick : 1; // isGuitarHero uint8_t : 1; - uint8_t leftShoulder : 1; // kick - uint8_t rightShoulder : 1; // orange + uint8_t leftShoulder : 1; // kick + uint8_t rightShoulder : 1; // orange uint8_t guide : 1; uint8_t : 1; - uint8_t a : 1; // green - uint8_t b : 1; // red - uint8_t x : 1; // blue - uint8_t y : 1; // yellow + uint8_t a : 1; // green + uint8_t b : 1; // red + uint8_t x : 1; // blue + uint8_t y : 1; // yellow uint8_t unused1[2]; int16_t unused2; @@ -228,8 +279,8 @@ typedef struct { uint8_t rid; uint8_t rsize; - uint8_t dpadUp : 1; // dpadStrumUp - uint8_t dpadDown : 1; // dpadStrumDown + uint8_t dpadUp : 1; // dpadStrumUp + uint8_t dpadDown : 1; // dpadStrumDown uint8_t dpadLeft : 1; uint8_t dpadRight : 1; @@ -238,15 +289,15 @@ typedef struct uint8_t : 1; uint8_t : 1; - uint8_t leftShoulder : 1; // orange - uint8_t rightShoulder : 1; // pedal + uint8_t leftShoulder : 1; // orange + uint8_t rightShoulder : 1; // pedal uint8_t guide : 1; uint8_t : 1; - uint8_t a : 1; // green - uint8_t b : 1; // red - uint8_t x : 1; // blue - uint8_t y : 1; // yellow + uint8_t a : 1; // green + uint8_t b : 1; // red + uint8_t x : 1; // blue + uint8_t y : 1; // yellow uint8_t accelZ; uint8_t accelX; @@ -261,25 +312,25 @@ typedef struct { uint8_t rid; uint8_t rsize; - uint8_t dpadUp : 1; // dpadStrumUp - uint8_t dpadDown : 1; // dpadStrumDown + uint8_t dpadUp : 1; // dpadStrumUp + uint8_t dpadDown : 1; // dpadStrumDown uint8_t dpadLeft : 1; uint8_t dpadRight : 1; uint8_t start : 1; uint8_t back : 1; - uint8_t solo : 1; // leftThumbClick + uint8_t solo : 1; // leftThumbClick uint8_t : 1; - uint8_t leftShoulder : 1; // orange + uint8_t leftShoulder : 1; // orange uint8_t : 1; uint8_t guide : 1; uint8_t : 1; - uint8_t a : 1; // green - uint8_t b : 1; // red - uint8_t x : 1; // blue - uint8_t y : 1; // yellow + uint8_t a : 1; // green + uint8_t b : 1; // red + uint8_t x : 1; // blue + uint8_t y : 1; // yellow uint8_t pickup; uint8_t unused1; @@ -294,25 +345,25 @@ typedef struct { uint8_t rid; uint8_t rsize; - uint8_t dpadUp : 1; // dpadStrumUp - uint8_t dpadDown : 1; // dpadStrumDown + uint8_t dpadUp : 1; // dpadStrumUp + uint8_t dpadDown : 1; // dpadStrumDown uint8_t dpadLeft : 1; uint8_t dpadRight : 1; uint8_t start : 1; uint8_t back : 1; - uint8_t solo : 1; // leftThumbClick + uint8_t solo : 1; // leftThumbClick uint8_t : 1; - uint8_t leftShoulder : 1; // orange + uint8_t leftShoulder : 1; // orange uint8_t : 1; uint8_t guide : 1; uint8_t : 1; - uint8_t a : 1; // green - uint8_t b : 1; // red - uint8_t x : 1; // blue - uint8_t y : 1; // yellow + uint8_t a : 1; // green + uint8_t b : 1; // red + uint8_t x : 1; // blue + uint8_t y : 1; // yellow uint16_t lowEFret : 5; uint16_t aFret : 5; @@ -336,8 +387,8 @@ typedef struct uint16_t highEFretVelocity : 7; uint16_t : 1; - uint8_t autoCal_Microphone; // When the sensor isn't activated, this - uint8_t autoCal_Light; // and this just duplicate the tilt axis + uint8_t autoCal_Microphone; // When the sensor isn't activated, this + uint8_t autoCal_Light; // and this just duplicate the tilt axis uint8_t tilt; uint8_t : 7; @@ -353,31 +404,75 @@ typedef struct { uint8_t rid; uint8_t rsize; - uint8_t dpadUp : 1; // dpadStrumUp - uint8_t dpadDown : 1; // dpadStrumDown + uint8_t dpadUp : 1; // dpadStrumUp + uint8_t dpadDown : 1; // dpadStrumDown uint8_t dpadLeft : 1; uint8_t dpadRight : 1; uint8_t start : 1; uint8_t back : 1; - uint8_t solo : 1; // leftThumbClick + uint8_t solo : 1; // leftThumbClick uint8_t : 1; - uint8_t leftShoulder : 1; // orange + uint8_t leftShoulder : 1; // orange uint8_t : 1; uint8_t guide : 1; uint8_t : 1; - uint8_t a : 1; // green - uint8_t b : 1; // red - uint8_t x : 1; // blue - uint8_t y : 1; // yellow - - uint8_t key1; - uint8_t key2; - uint8_t key3; - - uint8_t velocities[5]; + uint8_t a : 1; // green + uint8_t b : 1; // red + uint8_t x : 1; // blue + uint8_t y : 1; // yellow + union + { + struct + { + uint8_t key8 : 1; + uint8_t key7 : 1; + uint8_t key6 : 1; + uint8_t key5 : 1; + uint8_t key4 : 1; + uint8_t key3 : 1; + uint8_t key2 : 1; + uint8_t key1 : 1; + uint8_t key16 : 1; + uint8_t key15 : 1; + uint8_t key14 : 1; + uint8_t key13 : 1; + uint8_t key12 : 1; + uint8_t key11 : 1; + uint8_t key10 : 1; + uint8_t key9 : 1; + uint8_t key24 : 1; + uint8_t key23 : 1; + uint8_t key22 : 1; + uint8_t key21 : 1; + uint8_t key20 : 1; + uint8_t key19 : 1; + uint8_t key18 : 1; + uint8_t key17 : 1; + }; + uint8_t keys[3]; + }; + + union + { + struct + { + uint8_t velocity1 : 7; + uint8_t key25 : 1; + uint8_t velocity2 : 7; + uint8_t : 1; + uint8_t velocity3 : 7; + uint8_t : 1; + uint8_t velocity4 : 7; + uint8_t : 1; + uint8_t velocity5 : 7; + uint8_t : 1; + }; + + uint8_t velocities[5]; + }; uint8_t : 7; uint8_t overdrive : 1; @@ -389,7 +484,7 @@ typedef struct uint8_t unused2[4]; - uint8_t pedalConnection : 1; // If this matches PS3 MPA behavior, always 0 with the MIDI Pro Adapter + uint8_t pedalConnection : 1; // If this matches PS3 MPA behavior, always 0 with the MIDI Pro Adapter uint8_t : 7; } __attribute__((packed)) XInputRockBandKeyboard_Data_t; @@ -402,20 +497,20 @@ typedef struct uint8_t dpadLeft : 1; uint8_t dpadRight : 1; - uint8_t start : 1; // start, pause - uint8_t back : 1; // back, heroPower - uint8_t leftThumbClick : 1; // leftThumbClick, ghtv + uint8_t start : 1; // start, pause + uint8_t back : 1; // back, heroPower + uint8_t leftThumbClick : 1; // leftThumbClick, ghtv uint8_t : 1; - uint8_t leftShoulder : 1; // white2 leftShoulder - uint8_t rightShoulder : 1; // white3 rightShoulder + uint8_t leftShoulder : 1; // white2 leftShoulder + uint8_t rightShoulder : 1; // white3 rightShoulder uint8_t guide : 1; uint8_t : 1; - uint8_t a : 1; // black1 a - uint8_t b : 1; // black2 b - uint8_t x : 1; // white1 x - uint8_t y : 1; // black3 y + uint8_t a : 1; // black1 a + uint8_t b : 1; // black2 b + uint8_t x : 1; // white1 x + uint8_t y : 1; // black3 y uint8_t unused1[2]; @@ -449,7 +544,7 @@ typedef struct uint8_t a : 1; uint8_t b : 1; uint8_t x : 1; - uint8_t y : 1; // euphoria + uint8_t y : 1; // euphoria uint8_t leftGreen : 1; uint8_t leftRed : 1; @@ -464,7 +559,43 @@ typedef struct int16_t leftTableVelocity; int16_t rightTableVelocity; - int16_t effectsKnob; // Whether or not this is signed doesn't really matter, as either way it's gonna loop over when it reaches min/max + int16_t effectsKnob; // Whether or not this is signed doesn't really matter, as either way it's gonna loop over when it reaches min/max int16_t crossfader; uint8_t reserved_1[6]; } __attribute__((packed)) XInputTurntable_Data_t; + +typedef struct +{ + uint8_t rid; + uint8_t rsize; + uint8_t dpadUp : 1; + uint8_t dpadDown : 1; + uint8_t dpadLeft : 1; + uint8_t dpadRight : 1; + + uint8_t start : 1; + uint8_t back : 1; + uint8_t leftThumbClick : 1; + uint8_t rightThumbClick : 1; + + uint8_t leftShoulder : 1; + uint8_t rightShoulder : 1; + uint8_t guide : 1; + uint8_t : 1; + + uint8_t a : 1; + uint8_t b : 1; + uint8_t x : 1; + uint8_t y : 1; + + uint8_t penPressure; // starts at 0x72, goes up to 0xff + uint8_t accelZ; // 0x0a to 0x35 + uint8_t penX; // + uint8_t penY; + uint8_t status; // 0x40 = pen touch, 0x80 = single finger, anything else = multi touch + uint8_t distance; // distance between fingers for multitouch + uint8_t accelX; // 0x0a to 0x35 + uint8_t accelY; // 0x0a to 0x35 + uint8_t reserved_1[6]; + +} __attribute__((packed)) XInputUDraw_Data_t; diff --git a/include/shared_main.h b/include/shared_main.h index b4d9ff73b..6e82f57f3 100644 --- a/include/shared_main.h +++ b/include/shared_main.h @@ -1,7 +1,19 @@ #include "pin_funcs.h" #include "reports/controller_reports.h" #include "config.h" +#include "midi.hpp" +typedef struct { + uint8_t console_type; + uint8_t sub_type; + uint8_t dev_addr; + uint8_t instance; + uint8_t interface; + uint8_t drum_type; + uint8_t pickup; + uint8_t whammy; + bool xone_guide; +} USB_Device_Type_t; void init_main(void); void device_reset(void); @@ -9,8 +21,8 @@ void tick(void); void tick_wiioutput(); uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t output_console_type); void reset_usb(void); -uint32_t transfer_with_usb_controller(const uint8_t dev_addr, const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t wLength, uint8_t *buffer, bool* status); -void send_report_to_controller(uint8_t dev_addr, uint8_t instance, const uint8_t *report, uint8_t len); +uint32_t transfer_with_usb_controller(const USB_Device_Type_t dev, const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wLength, uint8_t *buffer, bool *status); +bool send_report_to_controller(uint8_t dev_addr, uint8_t instance, const uint8_t *report, uint8_t len); void send_report_to_pc(const void *report, uint8_t len); bool ready_for_next_packet(void); bool usb_configured(void); @@ -27,18 +39,13 @@ void on_connect(void); void set_console_type(uint8_t new_console_type); void authentication_successful(void); void onNote(uint8_t channel, uint8_t note, uint8_t velocity); +void onSysEx(uint8_t* array, unsigned size); void offNote(uint8_t channel, uint8_t note, uint8_t velocity); void onControlChange(uint8_t channel, uint8_t b1, uint8_t b2); void onPitchBend(uint8_t channel, int pitch); -typedef struct { - uint8_t console_type; - uint8_t sub_type; - uint8_t dev_addr; - uint8_t instance; -} USB_Device_Type_t; void get_usb_device_type_for(uint16_t vid, uint16_t pid, uint16_t version, USB_Device_Type_t *type); typedef struct { // If this bit is set, then an led effect (like star power) has overridden the leds @@ -105,6 +112,8 @@ extern USB_Host_Data_t last_usb_host_data; #endif extern USB_Host_Data_t bt_data; extern USB_LastReport_Data_t last_report_bt; +extern MidiDevice usbMidi; +extern MidiDevice serialMidi; #if BLUETOOTH_RX diff --git a/include/state_translation/drums.h b/include/state_translation/drums.h index c40c88c82..234d38664 100644 --- a/include/state_translation/drums.h +++ b/include/state_translation/drums.h @@ -12,128 +12,273 @@ bool blue = report->x; \ bool pad = report->padFlag; \ bool cymbal = report->cymbalFlag; \ - if (!red) { \ + if (!red) \ + { \ offNote(10, RB_MIDI_NOTE_RED, 0); \ } \ - if (!green) { \ + if (!green) \ + { \ offNote(10, RB_MIDI_NOTE_GREEN, 0); \ offNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, 0); \ } \ - if (!yellow) { \ + if (!yellow) \ + { \ offNote(10, RB_MIDI_NOTE_YELLOW, 0); \ offNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, 0); \ } \ - if (!blue) { \ + if (!blue) \ + { \ offNote(10, RB_MIDI_NOTE_BLUE, 0); \ offNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, 0); \ } \ - /* If you hit both the pad and cymbal of the same colour simultaneously, the velocity for the cymbal \ - is placed in the redVelocity, but the red button won't be pressed. */ \ - if (!red && redVelocity) { \ - if (up) { \ - onNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, redVelocity >> 1); \ - onNote(10, RB_MIDI_NOTE_YELLOW, yellowVelocity >> 1); \ - } else if (down) { \ - onNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, redVelocity >> 1); \ - onNote(10, RB_MIDI_NOTE_BLUE, blueVelocity >> 1); \ - } else { \ - onNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, redVelocity >> 1); \ - onNote(10, RB_MIDI_NOTE_GREEN, greenVelocity >> 1); \ - } \ - pad = false; \ - cymbal = false; \ - } \ - if (pad && cymbal) { \ + if (pad && cymbal) \ + { \ /* The d-pad inputs let us resolve the ambiguity of a pad+cymbal hit \ Only d-pad is checked here since it is the only unique identifier due to hardware bugs \ (sometimes the color flag is released before the d-pad input is, particularly at high polling rates)*/ \ \ - /* Yellow */ \ - if (up) { \ - onNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, yellowVelocity >> 1); \ - yellow = false; \ + /* If you hit both the pad and cymbal of the same colour simultaneously, the velocity for the cymbal \ + is placed in the redVelocity, but the red button won't be pressed. */ \ + if (!red && redVelocity) \ + { \ + if (up) \ + { \ + onNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, max(redVelocity >> 1, 1)); \ + onNote(10, RB_MIDI_NOTE_YELLOW, max(yellowVelocity >> 1, 1)); \ + } \ + else if (down) \ + { \ + onNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, max(redVelocity >> 1, 1)); \ + onNote(10, RB_MIDI_NOTE_BLUE, max(blueVelocity >> 1, 1)); \ + } \ + else \ + { \ + onNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, max(redVelocity >> 1, 1)); \ + onNote(10, RB_MIDI_NOTE_GREEN, max(greenVelocity >> 1, 1)); \ + } \ + pad = false; \ cymbal = false; \ } \ + else \ + { \ + /* Yellow */ \ + if (up) \ + { \ + onNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, max(yellowVelocity >> 1, 1)); \ + yellow = false; \ + cymbal = false; \ + } \ \ - /* Blue */ \ - if (down) { \ - onNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, blueVelocity >> 1); \ - blue = false; \ - cymbal = false; \ - } \ + /* Blue */ \ + if (down) \ + { \ + onNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, max(blueVelocity >> 1, 1)); \ + blue = false; \ + cymbal = false; \ + } \ \ - /* Green */ \ - if (!(up || down)) { \ - onNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, blueVelocity >> 1); \ - green = false; \ - cymbal = false; \ + /* Green */ \ + if (!(up || down)) \ + { \ + onNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, max(greenVelocity >> 1, 1)); \ + green = false; \ + cymbal = false; \ + } \ } \ } \ - if (pad) { \ - if (yellow) { \ - onNote(10, RB_MIDI_NOTE_YELLOW, yellowVelocity >> 1); \ + if (pad || device_type.drum_type == DRUM_RB1) \ + { \ + if (yellow) \ + { \ + onNote(10, RB_MIDI_NOTE_YELLOW, max(yellowVelocity >> 1, 1)); \ } \ - if (blue) { \ - onNote(10, RB_MIDI_NOTE_BLUE, blueVelocity >> 1); \ + if (blue) \ + { \ + onNote(10, RB_MIDI_NOTE_BLUE, max(blueVelocity >> 1, 1)); \ } \ - if (red) { \ - onNote(10, RB_MIDI_NOTE_RED, redVelocity >> 1); \ + if (red) \ + { \ + onNote(10, RB_MIDI_NOTE_RED, max(redVelocity >> 1, 1)); \ } \ - if (green) { \ - onNote(10, RB_MIDI_NOTE_GREEN, greenVelocity >> 1); \ + if (green) \ + { \ + onNote(10, RB_MIDI_NOTE_GREEN, max(greenVelocity >> 1, 1)); \ } \ } \ \ - if (cymbal) { \ - if (blue) { \ - onNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, blueVelocity >> 1); \ + if (cymbal) \ + { \ + if (blue) \ + { \ + onNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, max(blueVelocity >> 1, 1)); \ } \ - if (red) { \ - onNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, redVelocity >> 1); \ + if (yellow) \ + { \ + onNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, max(yellowVelocity >> 1, 1)); \ } \ - if (green) { \ - onNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, greenVelocity >> 1); \ + if (green) \ + { \ + onNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, max(greenVelocity >> 1, 1)); \ } \ } \ - if (kick1) { \ + if (kick1) \ + { \ onNote(10, RB_MIDI_NOTE_KICK, 0x7F); \ - } else { \ - offNote(10, RB_MIDI_NOTE_KICK, 0); \ } \ - if (kick2) { \ - onNote(10, RB_MIDI_NOTE_KICK2, 0x7F); \ - } else { \ - offNote(10, RB_MIDI_NOTE_KICK2, 0); \ + /*ion kits dont have the second pedal and send out signals like its always on, so ignore that*/ \ + if (device_type.drum_type != DRUM_ION) \ + { \ + if (kick2) \ + { \ + onNote(10, RB_MIDI_NOTE_KICK2, 0x7F); \ + } \ } - +#if DEVICE_TYPE == ROCK_BAND_DRUMS #define SET_GH_PADS() \ - if (report->greenVelocity) { \ - onNote(10, GH_MIDI_NOTE_GREEN, report->greenVelocity); \ - } else { \ - offNote(10, GH_MIDI_NOTE_GREEN, report->greenVelocity); \ + if (report->greenVelocity) \ + { \ + onNote(10, RB_MIDI_NOTE_GREEN, report->greenVelocity); \ + } \ + else \ + { \ + offNote(10, RB_MIDI_NOTE_GREEN, report->greenVelocity); \ + } \ + if (report->redVelocity) \ + { \ + onNote(10, RB_MIDI_NOTE_RED, report->redVelocity); \ } \ - if (report->redVelocity) { \ - onNote(10, GH_MIDI_NOTE_RED, report->redVelocity); \ - } else { \ - offNote(10, GH_MIDI_NOTE_RED, report->redVelocity); \ + else \ + { \ + offNote(10, RB_MIDI_NOTE_RED, report->redVelocity); \ } \ - if (report->yellowVelocity) { \ - onNote(10, GH_MIDI_NOTE_YELLOW, report->yellowVelocity); \ - } else { \ - offNote(10, GH_MIDI_NOTE_YELLOW, report->yellowVelocity); \ + if (report->yellowVelocity) \ + { \ + onNote(10, RB_MIDI_NOTE_YELLOW, report->yellowVelocity); \ } \ - if (report->blueVelocity) { \ - onNote(10, GH_MIDI_NOTE_BLUE, report->blueVelocity); \ - } else { \ - offNote(10, GH_MIDI_NOTE_BLUE, report->blueVelocity); \ + else \ + { \ + offNote(10, RB_MIDI_NOTE_YELLOW, report->yellowVelocity); \ } \ - if (report->orangeVelocity) { \ - onNote(10, GH_MIDI_NOTE_ORANGE, report->orangeVelocity); \ - } else { \ - offNote(10, GH_MIDI_NOTE_ORANGE, report->orangeVelocity); \ + if (report->blueVelocity) \ + { \ + onNote(10, RB_MIDI_NOTE_BLUE, report->blueVelocity); \ } \ - if (report->kickVelocity) { \ - onNote(10, GH_MIDI_NOTE_KICK, report->kickVelocity); \ - } else { \ - offNote(10, GH_MIDI_NOTE_KICK, report->kickVelocity); \ + else \ + { \ + offNote(10, RB_MIDI_NOTE_BLUE, report->blueVelocity); \ + } \ + if (report->orangeVelocity) \ + { \ + onNote(10, RB_MIDI_NOTE_GREEN, report->orangeVelocity); \ + } \ + else \ + { \ + offNote(10, RB_MIDI_NOTE_GREEN, report->orangeVelocity); \ + } \ + if (report->kickVelocity) \ + { \ + onNote(10, RB_MIDI_NOTE_KICK, report->kickVelocity); \ + } \ + else \ + { \ + offNote(10, RB_MIDI_NOTE_KICK, report->kickVelocity); \ + } +#else +#define SET_GH_PADS() \ + if (report->greenVelocity) \ + { \ + onNote(10, GH_REM_MIDI_NOTE_GREEN, report->greenVelocity); \ + } \ + else \ + { \ + offNote(10, GH_REM_MIDI_NOTE_GREEN, report->greenVelocity); \ + } \ + if (report->redVelocity) \ + { \ + onNote(10, GH_REM_MIDI_NOTE_RED, report->redVelocity); \ + } \ + else \ + { \ + offNote(10, GH_REM_MIDI_NOTE_RED, report->redVelocity); \ + } \ + if (report->yellowVelocity) \ + { \ + onNote(10, GH_REM_MIDI_NOTE_YELLOW, report->yellowVelocity); \ + } \ + else \ + { \ + offNote(10, GH_REM_MIDI_NOTE_YELLOW, report->yellowVelocity); \ + } \ + if (report->blueVelocity) \ + { \ + onNote(10, GH_REM_MIDI_NOTE_BLUE, report->blueVelocity); \ + } \ + else \ + { \ + offNote(10, GH_REM_MIDI_NOTE_BLUE, report->blueVelocity); \ + } \ + if (report->orangeVelocity) \ + { \ + onNote(10, GH_REM_MIDI_NOTE_ORANGE, report->orangeVelocity); \ + } \ + else \ + { \ + offNote(10, GH_REM_MIDI_NOTE_ORANGE, report->orangeVelocity); \ + } \ + if (report->kickVelocity) \ + { \ + onNote(10, GH_REM_MIDI_NOTE_KICK, report->kickVelocity); \ + } \ + else \ + { \ + offNote(10, GH_REM_MIDI_NOTE_KICK, report->kickVelocity); \ + } +#endif + +#if DEVICE_TYPE == ROCK_BAND_DRUMS +#define TRANSLATE_GH_MIDI(channel, note, velocity, func) \ + switch (note) \ + { \ + case GH_MIDI_NOTE_GREEN: \ + func(channel, RB_MIDI_NOTE_GREEN, velocity); \ + break; \ + case GH_MIDI_NOTE_RED: \ + func(channel, RB_MIDI_NOTE_RED, velocity); \ + break; \ + case GH_MIDI_NOTE_YELLOW: \ + func(channel, RB_MIDI_NOTE_YELLOW, velocity); \ + break; \ + case GH_MIDI_NOTE_BLUE: \ + func(channel, RB_MIDI_NOTE_BLUE, velocity); \ + break; \ + case GH_MIDI_NOTE_ORANGE: \ + func(channel, RB_MIDI_NOTE_GREEN, velocity); \ + break; \ + default: \ + func(channel, note, velocity); \ + break; \ + } +#else +#define TRANSLATE_GH_MIDI(channel, note, velocity, func) \ + switch (note) \ + { \ + case GH_MIDI_NOTE_GREEN: \ + func(channel, GH_REM_MIDI_NOTE_GREEN, velocity); \ + break; \ + case GH_MIDI_NOTE_RED: \ + func(channel, GH_REM_MIDI_NOTE_RED, velocity); \ + break; \ + case GH_MIDI_NOTE_YELLOW: \ + func(channel, GH_REM_MIDI_NOTE_YELLOW, velocity); \ + break; \ + case GH_MIDI_NOTE_BLUE: \ + func(channel, GH_REM_MIDI_NOTE_BLUE, velocity); \ + break; \ + case GH_MIDI_NOTE_ORANGE: \ + func(channel, GH_REM_MIDI_NOTE_ORANGE, velocity); \ + break; \ + default: \ + func(channel, note, velocity); \ + break; \ } +#endif \ No newline at end of file diff --git a/include/state_translation/pro_guitar.h b/include/state_translation/pro_guitar.h index d81d6d5f4..45a0ebe18 100644 --- a/include/state_translation/pro_guitar.h +++ b/include/state_translation/pro_guitar.h @@ -1,3 +1,25 @@ +#pragma once +typedef struct { + uint16_t lowEFret : 5; + uint16_t aFret : 5; + uint16_t dFret : 5; + uint16_t : 1; // always 0 + + uint16_t gFret : 5; + uint16_t bFret : 5; + uint16_t highEFret : 5; + uint16_t : 1; // always 0 + + uint8_t green :1; + uint8_t red :1; + uint8_t yellow :1; + uint8_t blue :1; + uint8_t orange :1; + uint8_t soloFlag : 1; + uint8_t : 1; // always 0 + uint8_t : 1; // always 0 +} __attribute__((packed)) protarneck_t; + #define TRANSLATE_PRO_GUITAR \ usb_host_data->lowEFretVelocity = report->lowEFretVelocity; \ usb_host_data->aFretVelocity = report->aFretVelocity; \ @@ -27,25 +49,26 @@ usb_host_data->bFret = report->bFret; \ usb_host_data->highEFret = report->highEFret; \ \ - usb_host_data->tilt |= report->tilt; \ + usb_host_data->tilt = report->tilt == 0x7F ? INT16_MAX : 0; \ /* TODO: pedalDigital should map to pedalDigital*/ \ usb_host_data->back |= report->pedal; -#define TRANSLATE_TO_PRO_GUITAR(item) \ - report->lowEFretVelocity = item.lowEFretVelocity; \ - report->aFretVelocity = item.aFretVelocity; \ - report->dFretVelocity = item.dFretVelocity; \ - report->gFretVelocity = item.gFretVelocity; \ - report->bFretVelocity = item.bFretVelocity; \ - report->highEFretVelocity = item.highEFretVelocity; \ - report->green = item.green; \ - report->red = item.red; \ - report->yellow = item.yellow; \ - report->blue = item.blue; \ - report->orange = item.orange; \ - report->lowEFret = item.lowEFret; \ - report->aFret = item.aFret; \ - report->dFret = item.dFret; \ - report->gFret = item.gFret; \ - report->bFret = item.bFret; \ +#define TRANSLATE_TO_PRO_GUITAR(item) \ + report->lowEFretVelocity = item.lowEFretVelocity; \ + report->aFretVelocity = item.aFretVelocity; \ + report->dFretVelocity = item.dFretVelocity; \ + report->gFretVelocity = item.gFretVelocity; \ + report->bFretVelocity = item.bFretVelocity; \ + report->highEFretVelocity = item.highEFretVelocity; \ + report->tilt = item.tilt == INT16_MAX ? 0x7F : 0x60; \ + report->green = item.green; \ + report->red = item.red; \ + report->yellow = item.yellow; \ + report->blue = item.blue; \ + report->orange = item.orange; \ + report->lowEFret = item.lowEFret; \ + report->aFret = item.aFret; \ + report->dFret = item.dFret; \ + report->gFret = item.gFret; \ + report->bFret = item.bFret; \ report->highEFret = item.highEFret; diff --git a/include/state_translation/pro_keys.h b/include/state_translation/pro_keys.h index faf73c15b..f1d852322 100644 --- a/include/state_translation/pro_keys.h +++ b/include/state_translation/pro_keys.h @@ -1,9 +1,7 @@ #define PRO_KEY_COUNT 25 #define PRO_KEY_FIRST_NOTE 24 #define DEFAULT_VELOCITY 64 -// Translate a Pro keys style report to a usb host report -// Note that we temporarily clear the buttons and then merge after -// As that makes it easier to process the velocities +// Translate a Pro keys style report to midi + usb host #define TRANSLATE_PRO_KEYS \ usb_host_data->a |= report->a; \ usb_host_data->b |= report->b; \ @@ -23,16 +21,15 @@ /* uint8 -> int14 (but only the positive half!) */ \ onPitchBend(0, report->touchPad << 5); \ uint32_t keyMask = \ - (report->key1 << 17) | \ - (report->key2 << 9) | \ - (report->key3 << 1) | \ - ((report->velocities[0] & 0x80) >> 7); \ + (((uint32_t)report->keys[0]) << 17) | \ + (((uint32_t)report->keys[1]) << 9) | \ + (((uint32_t)report->keys[2]) << 1) | \ + (((uint32_t)report->velocities[0] & 0x80) >> 7); \ \ - int pressed = 0; /* Number of keys pressed */ \ - int keyBit = 1 << (PRO_KEY_COUNT - 1); /* Bitmask used to test for a specific key */ \ - for (int i = 0; i < PRO_KEY_COUNT; i++) { \ + int pressed = 0; /* Number of keys pressed */ \ + for (uint32_t i = 0; i < PRO_KEY_COUNT; i++) { \ /* Check if the key is pressed */ \ - if (keyMask & keyBit) { \ + if (keyMask & (1 << (PRO_KEY_COUNT - 1 - i))) { \ /* There are only 5 key velocities stored*/ \ if (pressed < 5) { \ /* Retrieve velocity (ranges from 0-127)*/ \ @@ -43,7 +40,4 @@ } else { \ offNote(1, PRO_KEY_FIRST_NOTE + i, 0); \ } \ - \ - /* Shift the key mask to the next key*/ \ - keyMask >>= 1; \ } diff --git a/include/string_descriptors.h b/include/string_descriptors.h index f66d061e3..193cc0a17 100644 --- a/include/string_descriptors.h +++ b/include/string_descriptors.h @@ -44,6 +44,9 @@ extern const PROGMEM STRING_DESCRIPTOR xboxString; extern const PROGMEM STRING_DESCRIPTOR languageString; extern const PROGMEM STRING_DESCRIPTOR manufacturerString; extern const PROGMEM STRING_DESCRIPTOR productString; +extern const PROGMEM STRING_DESCRIPTOR rtString; +extern const PROGMEM STRING_DESCRIPTOR rtStringLED; +extern const PROGMEM STRING_DESCRIPTOR rtStringInput; #ifdef __cplusplus } #endif diff --git a/include/tusb_config.h b/include/tusb_config.h index 5142e5ae6..e9445aee7 100644 --- a/include/tusb_config.h +++ b/include/tusb_config.h @@ -19,7 +19,8 @@ #define CFG_TUD_XINPUT 8 #define CFG_TUH_XINPUT 8 #define CFG_TUSB_DEBUG 0 -#define CFG_TUH_MIDI 1 +#define CFG_TUH_MIDI 0 +#define CFG_TUH_MIDI_CUSTOM 1 // HID buffer size Should be sufficient to hold ID (if any) + Data #define CFG_TUH_ENUMERATION_BUFSIZE 512 diff --git a/include/usbhid.h b/include/usbhid.h new file mode 100644 index 000000000..e787621bf --- /dev/null +++ b/include/usbhid.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +This software may be distributed and modified under the terms of the GNU +General Public License version 2 (GPL2) as published by the Free Software +Foundation and appearing in the file GPL2.TXT included in the packaging of +this file. Please note that GPL2 Section 2[b] requires that all works based +on this software must also be made publicly available under the terms of +the GPL2 ("Copyleft"). + +Contact information +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ +#pragma once + +#include "Usb.h" + +#define MAX_REPORT_PARSERS 2 +#define HID_MAX_HID_CLASS_DESCRIPTORS 5 + +#define DATA_SIZE_MASK 0x03 +#define TYPE_MASK 0x0C +#define TAG_MASK 0xF0 + +#define DATA_SIZE_0 0x00 +#define DATA_SIZE_1 0x01 +#define DATA_SIZE_2 0x02 +#define DATA_SIZE_4 0x03 + +#define TYPE_MAIN 0x00 +#define TYPE_GLOBAL 0x04 +#define TYPE_LOCAL 0x08 + +#define TAG_MAIN_INPUT 0x80 +#define TAG_MAIN_OUTPUT 0x90 +#define TAG_MAIN_COLLECTION 0xA0 +#define TAG_MAIN_FEATURE 0xB0 +#define TAG_MAIN_ENDCOLLECTION 0xC0 + +#define TAG_GLOBAL_USAGEPAGE 0x00 +#define TAG_GLOBAL_LOGICALMIN 0x10 +#define TAG_GLOBAL_LOGICALMAX 0x20 +#define TAG_GLOBAL_PHYSMIN 0x30 +#define TAG_GLOBAL_PHYSMAX 0x40 +#define TAG_GLOBAL_UNITEXP 0x50 +#define TAG_GLOBAL_UNIT 0x60 +#define TAG_GLOBAL_REPORTSIZE 0x70 +#define TAG_GLOBAL_REPORTID 0x80 +#define TAG_GLOBAL_REPORTCOUNT 0x90 +#define TAG_GLOBAL_PUSH 0xA0 +#define TAG_GLOBAL_POP 0xB0 + +#define TAG_LOCAL_USAGE 0x00 +#define TAG_LOCAL_USAGEMIN 0x10 +#define TAG_LOCAL_USAGEMAX 0x20 + +/* HID requests */ +#define bmREQ_HID_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE +#define bmREQ_HID_IN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE +#define bmREQ_HID_REPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE + +/* HID constants. Not part of chapter 9 */ +/* Class-Specific Requests */ +#define HID_REQUEST_GET_REPORT 0x01 +#define HID_REQUEST_GET_IDLE 0x02 +#define HID_REQUEST_GET_PROTOCOL 0x03 +#define HID_REQUEST_SET_REPORT 0x09 +#define HID_REQUEST_SET_IDLE 0x0A +#define HID_REQUEST_SET_PROTOCOL 0x0B + +/* Class Descriptor Types */ +#define HID_DESCRIPTOR_HID 0x21 +#define HID_DESCRIPTOR_REPORT 0x22 +#define HID_DESRIPTOR_PHY 0x23 + +/* Protocol Selection */ +#define USB_HID_BOOT_PROTOCOL 0x00 +#define HID_RPT_PROTOCOL 0x01 + +/* HID Interface Class Code */ +#define HID_INTF 0x03 + +/* HID Interface Class SubClass Codes */ +#define HID_BOOT_INTF_SUBCLASS 0x01 + +/* HID Interface Class Protocol Codes */ +#define USB_HID_PROTOCOL_NONE 0x00 +#define USB_HID_PROTOCOL_KEYBOARD 0x01 +#define USB_HID_PROTOCOL_MOUSE 0x02 + +#define HID_ITEM_TYPE_MAIN 0 +#define HID_ITEM_TYPE_GLOBAL 1 +#define HID_ITEM_TYPE_LOCAL 2 +#define HID_ITEM_TYPE_RESERVED 3 + +#define HID_LONG_ITEM_PREFIX 0xfe // Long item prefix value + +#define bmHID_MAIN_ITEM_TAG 0xfc // Main item tag mask + +#define bmHID_MAIN_ITEM_INPUT 0x80 // Main item Input tag value +#define bmHID_MAIN_ITEM_OUTPUT 0x90 // Main item Output tag value +#define bmHID_MAIN_ITEM_FEATURE 0xb0 // Main item Feature tag value +#define bmHID_MAIN_ITEM_COLLECTION 0xa0 // Main item Collection tag value +#define bmHID_MAIN_ITEM_END_COLLECTION 0xce // Main item End Collection tag value + +#define HID_MAIN_ITEM_COLLECTION_PHYSICAL 0 +#define HID_MAIN_ITEM_COLLECTION_APPLICATION 1 +#define HID_MAIN_ITEM_COLLECTION_LOGICAL 2 +#define HID_MAIN_ITEM_COLLECTION_REPORT 3 +#define HID_MAIN_ITEM_COLLECTION_NAMED_ARRAY 4 +#define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5 +#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6 diff --git a/include/xbox.h b/include/xbox.h index b9151ea32..7d45d6fb4 100644 --- a/include/xbox.h +++ b/include/xbox.h @@ -2,10 +2,12 @@ #include "wcid.h" #include "reports/xinput_reports.h" #include "reports/og_xbox_reports.h" +// This actually just defines the supported report types! +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-xusbi/3beba8eb-25f9-4f80-bca8-d4665dd5b767 typedef struct { uint8_t bLength; // Length of this descriptor. uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). - uint8_t reserved[2]; + uint8_t reserved[2]; //version uint8_t subtype; uint8_t reserved2; uint8_t bEndpointAddressIn; @@ -16,6 +18,7 @@ typedef struct { uint8_t reserved4[2]; } __attribute__((packed)) XBOX_ID_DESCRIPTOR; + typedef struct { uint8_t bLength; // Length of this descriptor. uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). diff --git a/lib/fxpt_math/src/fxpt_math.h b/lib/fxpt_math/src/fxpt_math.h index d860c5e2d..cc0d7d308 100644 --- a/lib/fxpt_math/src/fxpt_math.h +++ b/lib/fxpt_math/src/fxpt_math.h @@ -47,6 +47,9 @@ extern "C" { #endif uint16_t fxpt_atan2(const int16_t y, const int16_t x); uint16_t fxpt_asin(int16_t x); +inline int16_t fxpt_atan2s(const int16_t y, const int16_t x) { + return fxpt_atan2(y, x); +} #ifdef __cplusplus } diff --git a/platformio.ini b/platformio.ini index c7e1dab53..52b1c5d2e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2,243 +2,6 @@ extra_scripts = pre:ardwiino_script_pre.py post:ardwiino_script_post.py -[micro] -build_flags = - -DUSB_HOST_SERIAL=Serial1 - -I src/avr/micro/shared - -I src/avr/shared - -include include/LUFAConfig.h -platform = atmelavr -board = micro -framework = arduino -board_upload.detect_frequency = true -board_upload.ardwiino_bootloader = true -board_upload.wait_for_upload_port = false -build_src_filter = - + - + - + - + - + -platform_packages = - framework-arduino-avr @ https://github.com/Santroller/framework-arduino-avr/archive/refs/heads/main.zip@5.1.0 - platformio/tool-avrdude@1.70200.0 - platformio/toolchain-atmelavr@3.70300.220127 -check_skip_packages = yes -lib_ignore = - Wire -lib_deps = - felis/USB-Host-Shield-20 @ ^1.6.0 - -[env:microdetect] -build_flags = - ${micro.build_flags} - -D DETECT -build_src_filter = - + - + - + -platform = atmelavr -board = micro -framework = arduino -platform_packages = - framework-arduino-avr @ https://github.com/Santroller/framework-arduino-avr/archive/refs/heads/main.zip@5.1.0 - platformio/tool-avrdude@1.70200.0 - platformio/toolchain-atmelavr@3.70300.220127 -check_skip_packages = yes -board_upload.wait_for_upload_port = false - - -[env:arduino_leonardo] -board = leonardo -build_flags = ${micro.build_flags} -extends = micro -board_upload.wait_for_upload_port = false - -[env:arduino_micro] -build_flags = ${micro.build_flags} -extends = micro -board_upload.wait_for_upload_port = false - -[env:sparkfun_promicro] -board = sparkfun_promicro16 -build_flags = ${micro.build_flags} -extends = micro -board_upload.wait_for_upload_port = false - -[env:sparkfun_promicro_8] -extends = env:sparkfun_promicro -board_upload.wait_for_upload_port = false -board_upload.detect_frequency = false -board_build.f_cpu=8000000L - -[env:sparkfun_promicro_16] -extends = env:sparkfun_promicro -board_upload.wait_for_upload_port = false -board_upload.detect_frequency = false -board_build.f_cpu=16000000L - -[env:arduino_micro_8] -extends = env:arduino_micro -board_upload.wait_for_upload_port = false -board_upload.detect_frequency = false -board_build.f_cpu=8000000L - -[env:arduino_micro_16] -extends = env:arduino_micro -board_upload.wait_for_upload_port = false -board_upload.detect_frequency = false -board_build.f_cpu=16000000L - -[env:arduino_leonardo_8] -extends = env:arduino_leonardo -board_upload.wait_for_upload_port = false -board_upload.detect_frequency = false -board_build.f_cpu=8000000L - -[env:arduino_leonardo_16] -extends = env:arduino_leonardo -board_upload.wait_for_upload_port = false -board_upload.detect_frequency = false -board_build.f_cpu=16000000L - - -[arduino_uno_mega_usb_parent] -platform = atmelavr -board = uno -build_src_filter = - + - + - + -platform_packages = - framework-arduino-avr @ https://github.com/Santroller/framework-arduino-avr/archive/refs/heads/main.zip@5.1.0 - platformio/toolchain-atmelavr@3.70300.220127 - platformio/tool-avrdude@1.70200.0 -check_skip_packages = yes -build_flags = - -DBOARD=BOARD_UNO - -Wl,--section-start=.data=0x800282 - -ffixed-r2 - -ffixed-r3 - -ffixed-r4 - -ffixed-r5 - -ffixed-r6 - -flto - -fuse-linker-plugin - -include include/LUFAConfig.h -upload_protocol = custom -upload_flags = - -F - -C - ${platformio.packages_dir}/tool-avrdude/avrdude.conf - -p - ${BOARD_MCU} - -c - flip1 - -u -upload_command = "${platformio.packages_dir}/tool-avrdude/avrdude" $UPLOAD_FLAGS -U flash:w:$SOURCE:i -lib_deps = https://github.com/Santroller/pio-bare-lufa/archive/refs/heads/main.zip@1.0.0 - -[env:arduino_uno_usb] -extends = arduino_uno_mega_usb_parent -build_flags = - ${arduino_uno_mega_usb_parent.build_flags} - -DPID=0x0001 -board_upload.detect_controller = true - -[env:arduino_mega_2560_usb] -extends = arduino_uno_mega_usb_parent -build_flags = - ${arduino_uno_mega_usb_parent.build_flags} - -DPID=0x0010 -board_upload.detect_controller = true - -[env:arduino_mega_adk_usb] -extends = arduino_uno_mega_usb_parent -build_flags = - ${arduino_uno_mega_usb_parent.build_flags} - -DPID=0x003f -board_upload.detect_controller = true - - -[env:arduino_uno_usb_serial] -extends = arduino_uno_mega_usb_parent -build_flags = - ${arduino_uno_mega_usb_parent.build_flags} - -DPID=0x0001 - -DSERIAL_ONLY=true -board_upload.detect_controller = true - -[env:arduino_mega_2560_usb_serial] -extends = arduino_uno_mega_usb_parent -build_flags = - ${arduino_uno_mega_usb_parent.build_flags} - -DPID=0x0010 - -DSERIAL_ONLY=true -board_upload.detect_controller = true - -[env:arduino_mega_adk_usb_serial] -extends = arduino_uno_mega_usb_parent -build_flags = - ${arduino_uno_mega_usb_parent.build_flags} - -DPID=0x003f - -DSERIAL_ONLY=true -board_upload.detect_controller = true - -[uno] -build_flags = - -I src/avr/uno/shared - -I src/avr/shared -platform = atmelavr -framework = arduino -build_src_filter = - + - + - + - + -check_skip_packages = yes -board_upload.wait_for_upload_port = false -lib_ignore = - Wire -lib_deps = - sukkopera/PsxNewLib@^0.4.0 - felis/USB-Host-Shield-20 @ ^1.6.0 -platform_packages = - framework-arduino-avr @ https://github.com/Santroller/framework-arduino-avr/archive/refs/heads/main.zip@5.1.0 - platformio/toolchain-atmelavr@3.70300.220127 - platformio/tool-avrdude@1.70200.0 - -[env:arduino_uno] -extends = uno -board = uno -board_upload.wait_for_upload_port = false - -[env:arduino_mega] -extends = uno -board_upload.wait_for_upload_port = false -build_flags = - ${uno.build_flags} - -DUSART_RX_vect=USART0_RX_vect - -DUSART_UDRE_vect=USART0_UDRE_vect -board = megaatmega1280 - -[env:arduino_mega_2560] -extends = uno -board_upload.wait_for_upload_port = false -build_flags = - ${uno.build_flags} - -DUSART_RX_vect=USART0_RX_vect - -DUSART_UDRE_vect=USART0_UDRE_vect -board = megaatmega2560 - -[env:arduino_mega_adk] -extends = uno -board_upload.wait_for_upload_port = false -build_flags = - ${uno.build_flags} - -DUSART_RX_vect=USART0_RX_vect - -DUSART_UDRE_vect=USART0_UDRE_vect -board = megaADK ; Raspberry Pi Pico boards [pico_parent] @@ -246,7 +9,7 @@ board_upload.ardwiino_bootloader_teensy = true board_build.use_usb = 1 platform = https://github.com/maxgerhardt/platform-raspberrypi/archive/39b90392af50585e429941bd2561a91949a2ba46.zip@1.15.0 platform_packages = - framework-arduinopico@https://github.com/Santroller/arduino-pico/releases/download/4.6.3-sanjay/rp2040-4.6.3-sanjay.zip@1.40404.0 + framework-arduinopico@https://github.com/Santroller/arduino-pico/releases/download/4.7.0-sanjay/rp2040-4.7.0-sanjay.zip@1.50404.0 board = pico framework = arduino board_build.core = earlephilhower @@ -260,8 +23,6 @@ build_src_filter = + + lib_deps = - https://github.com/Santroller/USB_Host_Shield_2.0/archive/refs/heads/master.zip@1.6.3 - fortyseveneffects/MIDI Library@5.0.2 SPI [pico] extends = pico_parent diff --git a/src/avr/lufa/LUFA.c b/src/avr/lufa/LUFA.c deleted file mode 100644 index bee5b7311..000000000 --- a/src/avr/lufa/LUFA.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "LUFAConfig.h" - -#include diff --git a/src/avr/lufa/reboot.c b/src/avr/lufa/reboot.c deleted file mode 100644 index 6d6d7d3ec..000000000 --- a/src/avr/lufa/reboot.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include -void reboot(void) { - cli(); - wdt_enable(WDTO_15MS); - for (;;) {} -} \ No newline at end of file diff --git a/src/avr/micro/detect/descriptors_detect.c b/src/avr/micro/detect/descriptors_detect.c deleted file mode 100644 index 074689a56..000000000 --- a/src/avr/micro/detect/descriptors_detect.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2013. - - dean [at] fourwalledcubicle [dot] com - www.lufa-lib.org -*/ - -/* - Copyright 2013 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 - * - * USB Device Descriptors, for library use when in USB device mode. Descriptors are special - * computer-readable structures which the host requests upon device enumeration, to determine - * the device's capabilities and functions. - */ - -#include "descriptors_detect.h" - -#include "progmem.h" -#include "wcid.h" - -uint8_t realFreq = 16; -const OS_DESCRIPTOR OSDescriptorString = { - bLength : sizeof(OS_DESCRIPTOR), - bDescriptorType : DTYPE_String, - Signature : {'M', 'S', 'F', 'T', '1', '0', '0'}, - VendorCode : REQ_GET_OS_FEATURE_DESCRIPTOR, - Reserved : 0 -}; -const USB_Descriptor_Device_t DeviceDescriptor = - { - .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, - - .USBSpecification = VERSION_BCD(2, 0, 0), - .Class = 0x02, - .SubClass = 0x00, - .Protocol = 0x00, - - .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE, - - .VendorID = 0x1209, - - .ProductID = 0x2886, - .ReleaseNumber = 0x0001, - - .ManufacturerStrIndex = STRING_ID_Manufacturer, - .ProductStrIndex = STRING_ID_Product, - .SerialNumStrIndex = USE_INTERNAL_SERIAL, - - .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS}; - -const USB_Descriptor_Configuration_t ConfigurationDescriptor = - { - .Config = - { - .Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration}, - - .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t), - .TotalInterfaces = 1, - - .ConfigurationNumber = 1, - .ConfigurationStrIndex = NO_DESCRIPTOR, - - .ConfigAttributes = 0, - - .MaxPowerConsumption = USB_CONFIG_POWER_MA(100)}, - .Interface = { - Header : - {Size : sizeof(USB_Descriptor_Interface_t), Type : DTYPE_Interface}, - InterfaceNumber : INTERFACE_ID_Device, - AlternateSetting : 0, - TotalEndpoints : 0, - Class : 0xFF, - SubClass : 0xFF, - Protocol : 0xFF, - InterfaceStrIndex : NO_DESCRIPTOR - }, -}; - -/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests - * the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate - * via the language ID table available at USB.org what languages the device supports for its string descriptors. - */ -const USB_Descriptor_String_t LanguageString = - { - .Header = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String}, - - .UnicodeString = {LANGUAGE_ID_ENG}}; - -/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable - * form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device - * Descriptor. - */ -const USB_Descriptor_String_t ManufacturerString = - { - .Header = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String}, - - .UnicodeString = L"sanjay900"}; - -/** Product descriptor string. This is a Unicode string containing the product's details in human readable form, - * and is read out upon request by the host when the appropriate string ID is requested, listed in the Device - * Descriptor. - */ -const USB_Descriptor_String_t ProductString16 = - { - .Header = {.Size = USB_STRING_LEN(56), .Type = DTYPE_String}, - - .UnicodeString = L"Ardwiino - Detect - 16000000"}; - -const USB_Descriptor_String_t ProductString8 = - { - .Header = {.Size = USB_STRING_LEN(54), .Type = DTYPE_String}, - - .UnicodeString = L"Ardwiino - Detect - 8000000"}; - -/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" - * documentation) by the application code so that the address and size of a requested descriptor can be given - * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function - * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the - * USB host. - */ -uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, - const uint16_t wIndex, - const void** const DescriptorAddress) { - const uint8_t DescriptorType = (wValue >> 8); - const uint8_t DescriptorNumber = (wValue & 0xFF); - - const void* Address = NULL; - uint16_t Size = NO_DESCRIPTOR; - - switch (DescriptorType) { - case DTYPE_Device: - Address = &DeviceDescriptor; - Size = sizeof(USB_Descriptor_Device_t); - break; - case DTYPE_Configuration: - Address = &ConfigurationDescriptor; - Size = sizeof(USB_Descriptor_Configuration_t); - break; - case DTYPE_String: - switch (DescriptorNumber) { - case STRING_ID_Language: - Address = &LanguageString; - Size = LanguageString.Header.Size; - break; - case STRING_ID_Manufacturer: - Address = &ManufacturerString; - Size = ManufacturerString.Header.Size; - break; - case STRING_ID_Product: - if (realFreq == 16) { - Address = &ProductString16; - Size = ProductString16.Header.Size; - } else { - Address = &ProductString8; - Size = ProductString8.Header.Size; - } - break; - case 0xEE: - Address = &OSDescriptorString; - Size = OSDescriptorString.bLength; - break; - } - - break; - } - - *DescriptorAddress = Address; - return Size; -} diff --git a/src/avr/micro/detect/descriptors_detect.h b/src/avr/micro/detect/descriptors_detect.h deleted file mode 100644 index 3b1be7b2c..000000000 --- a/src/avr/micro/detect/descriptors_detect.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2013. - - dean [at] fourwalledcubicle [dot] com - www.lufa-lib.org -*/ - -/* - Copyright 2013 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 Descriptors.c. - */ - -#ifndef _DESCRIPTORS_H_ -#define _DESCRIPTORS_H_ - -/* Includes: */ -#include "progmem.h" - -#include "endpoints.h" -#include "LUFAConfig.h" -#include - - -/* Type Defines: */ -/** Type define for the device configuration descriptor structure. This must be defined in the - * application code, as the configuration descriptor contains several sub-descriptors which - * vary between devices, and which describe the device's usage to the host. - */ -typedef struct -{ - USB_Descriptor_Configuration_Header_t Config; - - USB_Descriptor_Interface_t Interface; -} USB_Descriptor_Configuration_t; - -/** Enum for the device string descriptor IDs within the device. Each string descriptor should - * have a unique ID index associated with it, which can be used to refer to the string from - * other descriptors. - */ -enum StringDescriptors_t { - STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */ - STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */ - STRING_ID_Product = 2, /**< Product string ID */ -}; -extern uint8_t realFreq; -#endif diff --git a/src/avr/micro/detect/main.c b/src/avr/micro/detect/main.c deleted file mode 100644 index 4fe559a02..000000000 --- a/src/avr/micro/detect/main.c +++ /dev/null @@ -1,115 +0,0 @@ -/** - * You should have a LUFAConfig.h for this to work. - */ - -/** - * Include LUFA.h after LUFAConfig.h - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "commands.h" - -#include "bootloader.h" -#include "descriptors_detect.h" -#include "wcid.h" - -void SetupHardware(void); -char freqString[10]; -volatile bool waiting = true; - -const OS_COMPATIBLE_ID_DESCRIPTOR_SINGLE DevCompatIDs = { - TotalLength : sizeof(OS_COMPATIBLE_ID_DESCRIPTOR_SINGLE), - Version : 0x0100, - Index : DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR, - TotalSections : 1, - Reserved : {0}, - CompatID : { - { - FirstInterfaceNumber : INTERFACE_ID_Device, - Reserved : 0x04, - CompatibleID : "WINUSB", - SubCompatibleID : {0}, - Reserved2 : {0} - }} -}; -void setup() { - GlobalInterruptEnable(); // enable global interrupts - wdt_reset(); - // Enable the watchdog timer, as it runs from an internal clock so it will not be affected by the crystal - MCUSR &= ~_BV(WDRF); - /* Start the WDT Config change sequence. */ - WDTCSR |= _BV(WDCE) | _BV(WDE); - /* Configure the prescaler and the WDT for interrupt mode only*/ - WDTCSR = _BV(WDIE) | WDTO_15MS; - sei(); - long timeSinceWDT = millis(); - while (waiting) { - } - timeSinceWDT = millis() - timeSinceWDT; - realFreq = 16; - // And now compare to what we expect - if (F_CPU == 16000000 && timeSinceWDT < 10) { - // if the user is running at 8mhz, then it will run at half speed, thus it will take less than 15ms - realFreq = 8; - } - PLLCSR = 0; - if (realFreq == 8) { - PLLCSR = (0 | (1 << PLLE)); - } else if (realFreq == 16) { - PLLCSR = ((1 << PINDIV) | (1 << PLLE)); - } - itoa(realFreq, freqString, 10); - freqString[strlen(freqString)] = '\n'; - SetupHardware(); // ask LUFA to setup the hardware -} - -void loop() { -} - -/** Configures the board hardware and chip peripherals for the demo's functionality. */ -void SetupHardware(void) { - /* Disable watchdog if enabled by bootloader/fuses */ - MCUSR &= ~(1 << WDRF); - wdt_disable(); - - /* Disable clock division */ - clock_prescale_set(clock_div_1); - - /* Hardware Initialization */ - USB_Init(); -} - -ISR(WDT_vect) { - wdt_disable(); - waiting = false; -} - -/** Event handler for the library USB Configuration Changed event. */ -void EVENT_USB_Device_ConfigurationChanged(void) { -} - -/** Event handler for the library USB Control Request reception event. */ -void EVENT_USB_Device_ControlRequest(void) { - if (USB_ControlRequest.bmRequestType == 0xC0 && USB_ControlRequest.bRequest == REQ_GET_OS_FEATURE_DESCRIPTOR && USB_ControlRequest.wIndex == DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR) { - Endpoint_ClearSETUP(); - Endpoint_Write_Control_Stream_LE(&DevCompatIDs, sizeof(DevCompatIDs)); - Endpoint_ClearStatusStage(); - } - if (USB_ControlRequest.bmRequestType == 0x21) { - if (USB_ControlRequest.bRequest == COMMAND_REBOOT) { - reboot(); - } - if (USB_ControlRequest.bRequest == COMMAND_JUMP_BOOTLOADER) { - bootloader(); - } - } -} diff --git a/src/avr/micro/main/main.cpp b/src/avr/micro/main/main.cpp deleted file mode 100644 index 900ab8f55..000000000 --- a/src/avr/micro/main/main.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/** - * You should have a LUFAConfig.h for this to work. - */ - -#include "LUFAConfig.h" -/** - * Include LUFA.h after LUFAConfig.h - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "commands.h" -#include "config.h" -#include "descriptors.h" -#include "hid.h" -#include "shared_main.h" - -typedef struct -{ - USB_Descriptor_Header_t Header; - uint16_t UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 4]; -} __attribute__((packed)) SignatureDescriptor_t; -volatile uint16_t persistedConsoleType __attribute__((section(".noinit"))); -volatile uint16_t persistedConsoleTypeValid __attribute__((section(".noinit"))); -void SetupHardware(void); - -bool connected = false; -void EVENT_USB_Device_Connect(void) { -} - -void EVENT_USB_Device_Disconnect(void) { - connected = false; -} - -bool usb_configured() { - return connected; -} - -void setup() { - init_main(); - if (persistedConsoleTypeValid == 0x3A2F) { - consoleType = persistedConsoleType; - } else { - consoleType = 0; - } - GlobalInterruptEnable(); // enable global interrupts - SetupHardware(); // ask LUFA to setup the hardware -} - -uint8_t buf[255]; -void loop() { - tick(); - Endpoint_SelectEndpoint(DEVICE_EPADDR_OUT); - if (Endpoint_IsOUTReceived()) { - if (Endpoint_IsReadWriteAllowed()) { - uint8_t size = Endpoint_BytesInEndpoint(); - Endpoint_Read_Stream_LE(buf, size, NULL); - hid_set_report(buf, size, INTERRUPT_ID, INTERRUPT_ID); - } - Endpoint_ClearOUT(); - } -} -bool ready_for_next_packet() { - Endpoint_SelectEndpoint(DEVICE_EPADDR_IN); - return Endpoint_IsINReady(); -} -void send_report_to_pc(const void* report, uint8_t len) { - Endpoint_SelectEndpoint(DEVICE_EPADDR_IN); - Endpoint_Write_Stream_LE(report, len, NULL); - Endpoint_ClearIN(); -} - -void SetupHardware(void) { - /* Disable watchdog if enabled by bootloader/fuses */ - MCUSR &= ~(1 << WDRF); - wdt_disable(); - - /* Disable clock division */ - clock_prescale_set(clock_div_1); - - /* Hardware Initialization */ - USB_Init(); -} - -void EVENT_USB_Device_ControlRequest(void) { - if (controlRequestValid(USB_ControlRequest.bmRequestType, USB_ControlRequest.bRequest, USB_ControlRequest.wValue, USB_ControlRequest.wIndex, USB_ControlRequest.wLength)) { - if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_DIRECTION) == (REQDIR_DEVICETOHOST)) { - uint16_t len = controlRequest(USB_ControlRequest.bmRequestType, USB_ControlRequest.bRequest, USB_ControlRequest.wValue, USB_ControlRequest.wIndex, USB_ControlRequest.wLength, buf, NULL); - if (len) { - Endpoint_ClearSETUP(); - Endpoint_Write_Control_Stream_LE(buf, len); - Endpoint_ClearStatusStage(); - } - } else { - Endpoint_ClearSETUP(); - Endpoint_Read_Control_Stream_LE(buf, USB_ControlRequest.wLength); - controlRequest(USB_ControlRequest.bmRequestType, USB_ControlRequest.bRequest, USB_ControlRequest.wValue, USB_ControlRequest.wIndex, USB_ControlRequest.wLength, buf, NULL); - Endpoint_ClearStatusStage(); - } - } -} -void EVENT_USB_Device_ConfigurationChanged(void) { - uint8_t type = EP_TYPE_INTERRUPT; - uint8_t epsize = 0x20; - uint8_t epsizeOut = 0x08; - if (consoleType == WINDOWS || consoleType == XBOX360) { - epsizeOut = 0x20; - } - if (consoleType == MIDI_ID) { - type = EP_TYPE_BULK; - } - Endpoint_ConfigureEndpoint(DEVICE_EPADDR_IN, type, epsize, 2); - Endpoint_ConfigureEndpoint(DEVICE_EPADDR_OUT, type, epsizeOut, 2); - connected = true; -} - -static void USB_Device_GetInternalSerialDescriptor(void) { - SignatureDescriptor_t* desc = (SignatureDescriptor_t*)buf; - desc->Header.Type = DTYPE_String; - desc->Header.Size = USB_STRING_LEN((INTERNAL_SERIAL_LENGTH_BITS / 4) + 4); - - uint_reg_t CurrentGlobalInt = GetGlobalInterruptMask(); - GlobalInterruptDisable(); - - uint8_t SigReadAddress = INTERNAL_SERIAL_START_ADDRESS; - - for (uint8_t SerialCharNum = 0; SerialCharNum < (INTERNAL_SERIAL_LENGTH_BITS / 4); SerialCharNum++) { - uint8_t SerialByte = boot_signature_byte_get(SigReadAddress); - - if (SerialCharNum & 0x01) { - SerialByte >>= 4; - SigReadAddress++; - } - - SerialByte &= 0x0F; - - desc->UnicodeString[SerialCharNum] = cpu_to_le16((SerialByte >= 10) ? (('A' - 10) + SerialByte) : ('0' + SerialByte)); - } - - SetGlobalInterruptMask(CurrentGlobalInt); - - desc->UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4)] = '3'; - desc->UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 1] = consoleType + '0'; -#if DEVICE_TYPE_IS_GAMEPAD - desc->UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 2] = DEVICE_TYPE + '0'; - desc->UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 3] = WINDOWS_USES_XINPUT + '0'; -#else - desc->UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 2] = 'K'; - desc->UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 3] = '0'; -#endif -} - -uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, - const uint16_t wIndex, - const void** const descriptorAddress) { - *descriptorAddress = buf; - if (wValue == ((DTYPE_String << 8) | 3)) { - USB_Device_GetInternalSerialDescriptor(); - return sizeof(SignatureDescriptor_t); - } - return descriptorRequest(wValue, wIndex, buf); -} -void reset_usb(void) { - persistedConsoleType = consoleType; - persistedConsoleTypeValid = 0x3A2F; - reboot(); -} \ No newline at end of file diff --git a/src/avr/micro/shared/bootloader.c b/src/avr/micro/shared/bootloader.c deleted file mode 100644 index fb421fcbd..000000000 --- a/src/avr/micro/shared/bootloader.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include "endpoints.h" -#define MAGIC_KEY_POS 0x0800 -#define MAGIC_KEY 0x7777 -volatile uint16_t *const bootKeyPtr = (volatile uint16_t *)MAGIC_KEY_POS; -uint16_t bootKeyVal; - -void bootloader(void) { - // write magic key to ram - *bootKeyPtr = MAGIC_KEY; - - reboot(); -} \ No newline at end of file diff --git a/src/avr/micro/shared/bootloader.h b/src/avr/micro/shared/bootloader.h deleted file mode 100644 index 8bd77d0eb..000000000 --- a/src/avr/micro/shared/bootloader.h +++ /dev/null @@ -1,5 +0,0 @@ -#include -#include "endpoints.h" -#define MAGIC_KEY_POS 0x0800 -#define MAGIC_KEY 0x7777 -void bootloader(void); diff --git a/src/avr/shared/io.cpp b/src/avr/shared/io.cpp deleted file mode 100644 index f1a6f1bbf..000000000 --- a/src/avr/shared/io.cpp +++ /dev/null @@ -1,580 +0,0 @@ -#include "io.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "wii.h" - -#include "config.h" -#include "util.h" -#ifndef TWI_BUFFER_LENGTH -#include "string.h" -#define TWI_BUFFER_LENGTH 32 -#endif - -#define TWI_READY 0 -#define TWI_MRX 1 -#define TWI_MTX 2 -#define TWI_SRX 3 -#define TWI_STX 4 -volatile bool spi_acknowledged = false; - -static volatile uint8_t twi_state; -static volatile uint8_t twi_slarw; -static volatile uint8_t twi_sendStop; // should the transaction end with a stop -static volatile uint8_t twi_inRepStart; // in the middle of a repeated start - -static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; -static volatile uint8_t twi_masterBufferIndex; -static volatile uint8_t twi_masterBufferLength; - -static volatile uint8_t twi_error; -static volatile unsigned int twi_reg_addr; - -static volatile unsigned char twi_first_addr_flag; // set address flag -static volatile unsigned char twi_rw_len; // length of most recent operation - -void spi_begin() { -#ifdef GC_SPI_CLOCK - uint8_t clockDiv; - if (GC_SPI_CLOCK >= F_CPU / 2) { - clockDiv = 0; - } else if (GC_SPI_CLOCK >= F_CPU / 4) { - clockDiv = 1; - } else if (GC_SPI_CLOCK >= F_CPU / 8) { - clockDiv = 2; - } else if (GC_SPI_CLOCK >= F_CPU / 16) { - clockDiv = 3; - } else if (GC_SPI_CLOCK >= F_CPU / 32) { - clockDiv = 4; - } else if (GC_SPI_CLOCK >= F_CPU / 64) { - clockDiv = 5; - } else { - clockDiv = 7; - } - - // Invert the SPI2X bit - clockDiv ^= 0x1; - - uint8_t config = 0; -#if GC_SPI_CPHA == 1 - config |= _BV(CPHA); -#endif -#if GC_SPI_CPOL == 1 - config |= _BV(CPOL); -#endif -#if GC_SPI_MSBFIRST == 0 - config |= _BV(DORD); -#endif - SPCR = _BV(SPE) | _BV(MSTR) | config | ((clockDiv >> 1) & 0x03); - SPSR = clockDiv & 0x01; -#endif -} -uint8_t spi_transfer(SPI_BLOCK block, uint8_t data) { - SPDR = data; - asm volatile("nop"); - while (!(SPSR & _BV(SPIF))); - return SPDR; -} -void spi_high(SPI_BLOCK block) {} -void twi_init() { -#ifdef GC_TWI_CLOCK - twi_state = TWI_READY; - twi_sendStop = true; // default value - twi_inRepStart = false; - -// // activate internal pullups for twi. -#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || \ - defined(__AVR_ATmega328P__) - // activate internal pull-ups for twi - // as per note from atmega8 manual pg167 - sbi(PORTC, 4); - sbi(PORTC, 5); -#else - // activate internal pull-ups for twi - // as per note from atmega128 manual pg204 - sbi(PORTD, 0); - sbi(PORTD, 1); -#endif - - // initialize twi prescaler and bit rate - cbi(TWSR, TWPS0); - cbi(TWSR, TWPS1); -// No idea why, but the wii stuff just isnt stable at higher speeds than 15 on the 5v devices -// That does still end up being ~363636hz, which is pretty close to the 400000hz target -#if F_CPU == 16000000UL -#if ((F_CPU / GC_TWI_CLOCK) - 16) / 2 > 16 - TWBR = ((F_CPU / GC_TWI_CLOCK) - 16) / 2; -#else - TWBR = 16; -#endif -#else -// note: TWBR should be 10 or higher for master mode -#if ((F_CPU / GC_TWI_CLOCK) - 16) / 2 > 10 - TWBR = ((F_CPU / GC_TWI_CLOCK) - 16) / 2; -#else - TWBR = 10; -#endif -#endif - // enable twi module, acks, and twi interrupt - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); -#endif -#ifdef GC_TWI_RX - twi_reg_addr = 0; - - // set slave address - TWAR = WII_ADDR << 1; - - // enable twi module, acks, and twi interrupt - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); -#endif -} - -#ifdef PS2_ACK -ISR(INTERRUPT_PS2_ACK_VECT) { - spi_acknowledged = true; -} -void init_ack() { - cli(); - EICRA |= INTERRUPT_PS2_ACK_EICRA; - EIMSK |= _BV(INTERRUPT_PS2_ACK); - sei(); -} -#endif - - -// === MODIFIED === -static uint16_t TIMEOUT = 32767; - -bool twi_readFromPointerSlow(TWI_BLOCK block, uint8_t address, uint8_t pointer, uint8_t length, - uint8_t *data) { - if (!twi_writeTo(block, address, &pointer, 1, true, true)) return false; - _delay_us(180); - return twi_readFrom(block, address, data, length, true); -} -bool twi_readFrom(TWI_BLOCK block, uint8_t address, uint8_t *data, uint8_t length, - uint8_t sendStop) { - // ensure data will fit into buffer - if (TWI_BUFFER_LENGTH < length) return 0; - - uint16_t timeoutCounter; - - // === MODIFIED === - // wait until twi is ready, become master receiver - if (TIMEOUT == 0) { - while (TWI_READY != twi_state) continue; - } else { - timeoutCounter = TIMEOUT; - while (TWI_READY != twi_state) { - //_delay_ms( TIMEOUT_TICK ); - timeoutCounter--; - if (timeoutCounter == 0) return 0; - } - } - /* - // wait until twi is ready, become master receiver - while(TWI_READY != twi_state){ - continue; - } - */ - - twi_state = TWI_MRX; - twi_sendStop = sendStop; - // reset error state (0xFF.. no error occured) - twi_error = 0xFF; - - // initialize buffer iteration vars - twi_masterBufferIndex = 0; - twi_masterBufferLength = length - 1; // This is not intuitive, read on... - // On receive, the previously configured ACK/NACK setting is transmitted in - // response to the received byte before the interrupt is signalled. - // Therefor we must actually set NACK when the _next_ to last byte is - // received, causing that NACK to be sent in response to receiving the last - // expected byte of data. - - // build sla+w, slave device address + w bit - twi_slarw = TW_READ; - twi_slarw |= address << 1; - - if (twi_inRepStart) { - // if we're in the repeated start state, then we've already sent the start, - // (@@@ we hope), and the TWI statemachine is just waiting for the address - // byte. We need to remove ourselves from the repeated start state before we - // enable interrupts, since the ISR is ASYNC, and we could get confused if - // we hit the ISR before cleaning up. Also, don't enable the START - // interrupt. There may be one pending from the repeated start that we sent - // ourselves, and that would really confuse things. - twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR - - // === MODIFIED === - if (TIMEOUT == 0) { - do { - TWDR = twi_slarw; - } while (TWCR & _BV(TWWC)); - } else { - timeoutCounter = TIMEOUT; - TWDR = twi_slarw; - while (TWCR & _BV(TWWC)) { - //_delay_ms( TIMEOUT_TICK ); - timeoutCounter--; - if (timeoutCounter == 0) return false; - TWDR = twi_slarw; - } - } - /* - do { - TWDR = twi_slarw; - } while(TWCR & _BV(TWWC)); - */ - TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | - _BV(TWIE); // enable INTs, but not START - } else { - // send start condition - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); - } - - // === MODIFIED === - // wait for read operation to complete - if (TIMEOUT == 0) { - while (TWI_MRX == twi_state) continue; - } else { - timeoutCounter = TIMEOUT; - while (TWI_MRX == twi_state) { - //_delay_ms( TIMEOUT_TICK ); - timeoutCounter--; - if (timeoutCounter == 0) return false; - } - } - /* - // wait for read operation to complete - while(TWI_MRX == twi_state){ - continue; - } - */ - - if (twi_masterBufferIndex < length) length = twi_masterBufferIndex; - // copy twi buffer to data - memcpy(data, twi_masterBuffer, length); - - return length; -} - -bool twi_writeTo(TWI_BLOCK block, uint8_t address, uint8_t *data, uint8_t length, uint8_t wait, - uint8_t sendStop) { - // ensure data will fit into buffer - if (TWI_BUFFER_LENGTH < length) return false; - - // === MODIFIED === - uint16_t timeoutCounter; - // wait until twi is ready, become master transmitter - if (TIMEOUT == 0) { - while (TWI_READY != twi_state) continue; - } else { - timeoutCounter = TIMEOUT; - while (TWI_READY != twi_state) { - //_delay_ms( TIMEOUT_TICK ); - timeoutCounter--; - if (timeoutCounter == 0) return false; - } - } - /* - // wait until twi is ready, become master transmitter - while( TWI_READY != twi_state ) { - continue; - } - */ - - twi_state = TWI_MTX; - twi_sendStop = sendStop; - // reset error state (0xFF.. no error occured) - twi_error = 0xFF; - - // initialize buffer iteration vars - twi_masterBufferIndex = 0; - twi_masterBufferLength = length; - - // copy data to twi buffer - memcpy(twi_masterBuffer, data, length); - // build sla+w, slave device address + w bit - twi_slarw = TW_WRITE; - twi_slarw |= address << 1; - - // if we're in a repeated start, then we've already sent the START - // in the ISR. Don't do it again. - if (twi_inRepStart) { - // if we're in the repeated start state, then we've already sent the start, - // (@@@ we hope), and the TWI statemachine is just waiting for the address - // byte. We need to remove ourselves from the repeated start state before we - // enable interrupts, since the ISR is ASYNC, and we could get confused if - // we hit the ISR before cleaning up. Also, don't enable the START - // interrupt. There may be one pending from the repeated start that we sent - // outselves, and that would really confuse things. - twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR - - // === MODIFIED === - if (TIMEOUT == 0) { - do { - TWDR = twi_slarw; - } while (TWCR & _BV(TWWC)); - } else { - timeoutCounter = TIMEOUT; - TWDR = twi_slarw; - while (TWCR & _BV(TWWC)) { - //_delay_ms( TIMEOUT_TICK ); - timeoutCounter--; - if (timeoutCounter == 0) return false; - TWDR = twi_slarw; - } - } - /* - do { - TWDR = twi_slarw; - } while(TWCR & _BV(TWWC)); - */ - - TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | - _BV(TWIE); // enable INTs, but not START - } else { - // send start condition - TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | - _BV(TWSTA); // enable INTs - } - - // === MODIFIED === - // wait for write operation to complete - if (TIMEOUT == 0) { - while (wait && (TWI_MTX == twi_state)) continue; - } else { - timeoutCounter = TIMEOUT; - while (wait && (TWI_MTX == twi_state)) { - //_delay_ms( TIMEOUT_TICK ); - timeoutCounter--; - if (timeoutCounter == 0) return false; - } - } - /* - // wait for write operation to complete - while(wait && (TWI_MTX == twi_state)){ - continue; - }*/ - - return twi_error == 0xFF; -} - -void twi_reply(uint8_t ack) { - // transmit master read ready signal, with or without ack - if (ack) { - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); - } else { - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); - } -} - -void twi_releaseBus(void) { - // release bus - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); - - // update twi state - twi_state = TWI_READY; -} - -bool twi_stop(void) { - // send stop condition - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); - - // === MODIFIED === - // wait for stop condition to be exectued on bus - // TWINT is not set after a stop condition! - if (TIMEOUT == 0) { - while (TWCR & _BV(TWSTO)) continue; - } else { - uint16_t timeoutCounter = TIMEOUT; - while (TWCR & _BV(TWSTO)) { - //_delay_ms( TIMEOUT_TICK ); - timeoutCounter--; - if (timeoutCounter == 0) return false; - } - } - /* - while(TWCR & _BV(TWSTO)){ - continue; - } - */ - - // update twi state - twi_state = TWI_READY; - return true; -} - -ISR(TWI_vect) { - switch (TW_STATUS) { - // All Master - case TW_START: // sent start condition - case TW_REP_START: // sent repeated start condition - // copy device address and r/w bit to output register and ack - TWDR = twi_slarw; - twi_reply(1); - break; - - // Master Transmitter - case TW_MT_SLA_ACK: // slave receiver acked address - case TW_MT_DATA_ACK: // slave receiver acked data - // if there is data to send, send it, otherwise stop - if (twi_masterBufferIndex < twi_masterBufferLength) { - // copy data to output register and ack - TWDR = twi_masterBuffer[twi_masterBufferIndex++]; - twi_reply(1); - } else { - if (twi_sendStop) - twi_stop(); - else { - twi_inRepStart = true; // we're gonna send the START - // don't enable the interrupt. We'll generate the start, but we - // avoid handling the interrupt until we're in the next transaction, - // at the point where we would normally issue the start. - TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); - twi_state = TWI_READY; - } - } - break; - case TW_MT_SLA_NACK: // address sent, nack received - twi_error = TW_MT_SLA_NACK; - twi_stop(); - break; - case TW_MT_DATA_NACK: // data sent, nack received - twi_error = TW_MT_DATA_NACK; - twi_stop(); - break; - case TW_MT_ARB_LOST: // lost bus arbitration - twi_error = TW_MT_ARB_LOST; - twi_releaseBus(); - break; - - // Master Receiver - case TW_MR_DATA_ACK: // data received, ack sent - // put byte into buffer - twi_masterBuffer[twi_masterBufferIndex++] = TWDR; - case TW_MR_SLA_ACK: // address sent, ack received - // ack if more bytes are expected, otherwise nack - if (twi_masterBufferIndex < twi_masterBufferLength) { - twi_reply(1); - } else { - twi_reply(0); - } - break; - case TW_MR_DATA_NACK: // data received, nack sent - // put final byte into buffer - twi_masterBuffer[twi_masterBufferIndex++] = TWDR; - if (twi_sendStop) - twi_stop(); - else { - twi_inRepStart = true; // we're gonna send the START - // don't enable the interrupt. We'll generate the start, but we - // avoid handling the interrupt until we're in the next transaction, - // at the point where we would normally issue the start. - TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); - twi_state = TWI_READY; - } - break; - case TW_MR_SLA_NACK: // address sent, nack received - twi_stop(); - break; - // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case - - // All - case TW_NO_INFO: // no state information - break; - case TW_BUS_ERROR: // bus error, illegal stop/start - twi_error = TW_BUS_ERROR; - twi_stop(); - break; -#ifdef GC_TWI_RX - // Slave Rx - case TW_SR_SLA_ACK: // addressed, returned ack - case TW_SR_GCALL_ACK: // addressed generally, returned ack - case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack - case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration generally, returned ack - // get ready to receive pointer - twi_first_addr_flag = 0; - // ack - twi_reply(1); - break; - case TW_SR_DATA_ACK: // data received, returned ack - case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack - if (twi_first_addr_flag != 0) { - // put byte in register - unsigned char t = TWDR; - twi_reg_addr++; - twi_rw_len++; - } else { - // set address - twi_reg_addr = TWDR; - twi_first_addr_flag = 1; - twi_rw_len = 0; - } - twi_reply(1); // ack - break; - case TW_SR_STOP: // stop or repeated start condition received - // run user defined function - recv_end(twi_reg_addr - twi_rw_len, twi_rw_len); - twi_reply(1); // ack future responses - break; - case TW_SR_DATA_NACK: // data received, returned nack - case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack - twi_reply(0); // nack back at master - break; - - // Slave Tx - case TW_ST_SLA_ACK: // addressed, returned ack - case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack - twi_rw_len = 0; - case TW_ST_DATA_ACK: // byte sent, ack returned - // ready output byte - TWDR = req_data(twi_reg_addr); - twi_reg_addr++; - twi_rw_len++; - twi_reply(1); // ack - break; - case TW_ST_DATA_NACK: // received nack, we are done - case TW_ST_LAST_DATA: // received ack, but we are done already! - // ack future responses - twi_reply(1); - break; - default: - twi_reply(0); - break; -#endif - } -} -#define INTERNAL_SERIAL_START_ADDRESS 0x0E -void read_serial(uint8_t *id, uint8_t len) { - uint8_t oldSREG = SREG; - cli(); - - uint8_t SigReadAddress = INTERNAL_SERIAL_START_ADDRESS; - - for (uint8_t SerialCharNum = 0; SerialCharNum < len; SerialCharNum++) { - uint8_t SerialByte = boot_signature_byte_get(SigReadAddress); - - if (SerialCharNum & 0x01) { - SerialByte >>= 4; - SigReadAddress++; - } - - SerialByte &= 0x0F; - - id[SerialCharNum] = (SerialByte >= 10) ? (('A' - 10) + SerialByte) : ('0' + SerialByte); - } - - SREG = oldSREG; -} -void go_to_sleep() { - // TODO: sleep is current pico only. -} \ No newline at end of file diff --git a/src/avr/shared/io_define.h b/src/avr/shared/io_define.h deleted file mode 100644 index c82ea080e..000000000 --- a/src/avr/shared/io_define.h +++ /dev/null @@ -1,44 +0,0 @@ -#include -#ifdef __AVR_ATmega328P__ -#define NUM_TOTAL_PINS 24 -#define PORT_COUNT 3 -#define PORTS \ - { (uint16_t) &PORTB, (uint16_t)&PORTC, (uint16_t)&PORTD } -// PC0-5 -#define ANALOG_MASK \ - { 0, 0b11111, 0 } -#define ANALOG_PORT(chan) &PORTC -#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -#define NUM_TOTAL_PINS 70 -#define PORT_COUNT 11 -#define PORTS \ - { (uint16_t) &PORTA, (uint16_t)&PORTB, (uint16_t)&PORTC, (uint16_t)&PORTD, (uint16_t)&PORTE, (uint16_t)&PORTF, (uint16_t)&PORTG, (uint16_t)&PORTH, (uint16_t)&PORTJ, (uint16_t)&PORTK, (uint16_t)&PORTL } -// PF and PK -#define ANALOG_MASK \ - { 0, 0, 0, 0, 0, 0xff, 0, 0, 0, 0xff, 0 } -#define ANALOG_PORT(chan) chan <= 7 ? &PORTF : &PORTK -#elif defined(__AVR_ATmega32U4__) -#define NUM_TOTAL_PINS 24 -#define PORT_COUNT 5 -#define PORTS \ - { (uint16_t) &PORTB, (uint16_t)&PORTC, (uint16_t)&PORTD, (uint16_t)&PORTE, (uint16_t)&PORTF } -// PF0-1 PF4-7 PB4-6 PD4,6,7 -#define ANALOG_MASK \ - { 0b0001111, 0, 0b00001011, 0, 0b1101111 } -#define ANALOG_PORT(chan) chan <= 7 ? &PORTF : (chan <= 10 ? &PORTD : &PORTB) -#elif defined(__AVR_AT90USB1286__) -#define NUM_TOTAL_PINS 44 -#define PORT_COUNT 6 -#define PORTS \ - { (uint16_t) &PORTA, (uint16_t) &PORTB, (uint16_t)&PORTC, (uint16_t)&PORTD, (uint16_t)&PORTE, (uint16_t)&PORTF } -// PF -#define ANALOG_MASK \ - { 0, 0, 0, 0, 0, 0xff } -#define ANALOG_PORT(chan) &PORTF -#endif - - -#define TWI_BLOCK void* -#define SPI_BLOCK void* -#define GC_TWI NULL -#define GC_SPI NULL \ No newline at end of file diff --git a/src/avr/shared/pins.cpp b/src/avr/shared/pins.cpp deleted file mode 100644 index cee2eb1e8..000000000 --- a/src/avr/shared/pins.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include -#include -#include - -#include "Arduino.h" -#include "config.h" -#include "io_define.h" -#include "progmem.h" -#include "util.h" - -volatile uint16_t adcReading[ADC_COUNT]; -const uint8_t analogPins[ADC_COUNT] = ADC_PINS; -const uint16_t PROGMEM ports[PORT_COUNT] = PORTS; -uint16_t adc(uint8_t pin) { - return adcReading[pin]; -} - -uint8_t digital_read(uint8_t port_num, uint8_t mask) { - volatile uint8_t* port = ((volatile uint8_t*)(pgm_read_word(ports + port_num))); - volatile uint8_t* ddr = port - 1; - volatile uint8_t* pin = port - 2; - uint8_t prevPort = *port; - uint8_t prevDdr = *ddr; - uint8_t oldSREG = SREG; - cli(); - // Set direction to input - *ddr &= ~mask; - // Enable pullup - *port |= mask; - delay(10); - uint8_t data = *pin; - // Revert the settings we changed - *port = prevPort; - *ddr = prevDdr; - SREG = oldSREG; - return data; -} - -void digital_write(uint8_t port_num, uint8_t mask, uint8_t activeMask) { - volatile uint8_t* port = ((volatile uint8_t*)(pgm_read_word(ports + port_num))); - volatile uint8_t* ddr = port - 1; - uint8_t oldSREG = SREG; - cli(); - // set pins in mask to output - *ddr |= mask; - *port &= ~mask; - // And then drive them high / low as necessary - *port |= activeMask; - SREG = oldSREG; -} - -uint16_t adc_read(uint8_t pin, uint8_t mask) { -#if ADC_COUNT != 0 - cbi(ADCSRA, ADIE); - while (bit_is_set(ADCSRA, ADSC)) - ; -#endif - // bit 7 is used as a flag for pin detection mode - bool detection = pin & (1 << 7); - pin &= ~(1 << 7); - - // When we are not doing pin detection, we don't want to be fiddling with the ports - volatile uint8_t* port = ANALOG_PORT(pin); - volatile uint8_t* ddr = port - 1; - uint8_t prevPort = *port; - uint8_t prevDdr = *ddr; - if (detection) { - uint8_t oldSREG = SREG; - cli(); - // Clear DDRx (input) - *ddr &= ~mask; - // Set PORTx (pull_up) - *port |= mask; - SREG = oldSREG; - } -#if defined(ADCSRB) && defined(MUX5) - // the MUX5 bit of ADCSRB selects whether we're reading from channels - // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). - ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); -#endif - - // set the analog reference (high two bits of ADMUX) and select the - // channel (low 4 bits). this also sets ADLAR (left-adjust result) - // to 0 (the default). - - ADMUX = (1 << 6) | (pin & 0x07); - - // Give things time to settle - delayMicroseconds(10); - sbi(ADCSRA, ADSC); - while (bit_is_set(ADCSRA, ADSC)) - ; - uint16_t data = ADC << 6; - if (detection) { - // Revert the settings we changed - uint8_t oldSREG = SREG; - cli(); - *port = prevPort; - *ddr = prevDdr; - SREG = oldSREG; - } -#if ADC_COUNT != 0 - sbi(ADCSRA, ADIE); - sbi(ADCSRA, ADSC); -#endif - return data; -} -void initPins(void) { - PIN_INIT; - sbi(ADCSRA, ADPS2); - cbi(ADCSRA, ADPS1); - cbi(ADCSRA, ADPS0); -#if ADC_COUNT != 0 - uint8_t pin = analogPins[0]; - -#if defined(ADCSRB) && defined(MUX5) - // the MUX5 bit of ADCSRB selects whether we're reading from channels - // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). - ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); -#endif - - // set the analog reference (high two bits of ADMUX) and select the - // channel (low 4 bits). this also sets ADLAR (left-adjust result) - // to 0 (the default). - - ADMUX = (1 << 6) | (pin & 0x07); - - sbi(ADCSRA, ADIE); - sbi(ADCSRA, ADSC); -#endif -} -int currentAnalog = 0; -#if ADC_COUNT != 0 -ISR(ADC_vect) { - adcReading[currentAnalog] = ADC << 6; - currentAnalog++; - if (currentAnalog == ADC_COUNT) { - currentAnalog = 0; - } - uint8_t pin = analogPins[currentAnalog]; - -#if defined(ADCSRB) && defined(MUX5) - // the MUX5 bit of ADCSRB selects whether we're reading from channels - // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). - ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); -#endif - - // set the analog reference (high two bits of ADMUX) and select the - // channel (low 4 bits). this also sets ADLAR (left-adjust result) - // to 0 (the default). - - ADMUX = (1 << 6) | (pin & 0x07); - - sbi(ADCSRA, ADSC); -} -#endif \ No newline at end of file diff --git a/src/avr/shared/ps2_emu.cpp b/src/avr/shared/ps2_emu.cpp deleted file mode 100644 index af6caebb0..000000000 --- a/src/avr/shared/ps2_emu.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include - -#include "Arduino.h" -#include "config.h" -#include "io.h" -#include "ps2.h" -#include "util.h" - -#ifdef TICK_PS2 - -uint8_t configMode = 0; -uint8_t mode = 0x41; - -uint8_t receiveCommand() { - uint8_t modeByte = configMode ? 0xF3 : mode; - PS2_OUTPUT_ACK_SET(); - uint8_t ret = spi_transfer(PS2_OUTPUT_SPI_PORT, 0xFF); - PS2_OUTPUT_ACK_CLEAR(); - sleep_us(2); - PS2_OUTPUT_ACK_SET(); - if (ret != 1) { - return 0; - } - ret = spi_transfer(PS2_OUTPUT_SPI_PORT, mode); - PS2_OUTPUT_ACK_CLEAR(); - return ret; -} -uint8_t receiveAll(uint8_t* data, uint8_t len) { - for (int i = 0; i < len - 1; i++) { - PS2_OUTPUT_ACK_SET(); - data[i] = spi_transfer(PS2_OUTPUT_SPI_PORT, data[i]); - PS2_OUTPUT_ACK_CLEAR(); - sleep_us(2); - } - PS2_OUTPUT_ACK_SET(); - data[len - 1] = spi_transfer(PS2_OUTPUT_SPI_PORT, data[len - 1]); - return len; -} -uint8_t receiveAll2(uint8_t* data0, uint8_t* data1, uint8_t len) { - uint8_t* data = data0; - for (int i = 0; i < len - 1; i++) { - PS2_OUTPUT_ACK_SET(); - data0[i] = spi_transfer(PS2_OUTPUT_SPI_PORT, data[i]); - if (data0[1] == 1) { - data = data1; - } - PS2_OUTPUT_ACK_CLEAR(); - } - PS2_OUTPUT_ACK_SET(); - data[len - 1] = spi_transfer(PS2_OUTPUT_SPI_PORT, data[len - 1]); - return len; -} -int counter = 0; - -uint8_t buttons1 = 0xff; -uint8_t buttons2 = 0xff; - -uint8_t motorSetting1 = 0xff; -uint8_t motorSetting2 = 0xff; - -bool analogEnabled = 0; - -int timeoutCounter = 0; -uint8_t cmd; -uint8_t param1; -uint8_t param2; -uint8_t param3; -void ps2_emu_init() { - PS2_OUTPUT_ACK_SET(); - cmd = 0; - param1 = 0; - param2 = 0; - param3 = 0; -// Guitars need to hold dpad left -#if DEVICE_TYPE_IS_GUITAR - buttons1 &= ~0x80; -#endif - -} -bool ps2_emu_tick(PS2_REPORT* report) { - if (PS2_OUTPUT_ATT_READ()) { - timeoutCounter++; - if (timeoutCounter >= 30000) // we've been disconnected - { - mode = 0x41; - motorSetting1 = 0xff; - motorSetting2 = 0xff; - analogEnabled = 0; - configMode = 0; - timeoutCounter = 0; - } - return false; - } - timeoutCounter = 0; - while (1) { - cmd = receiveCommand(); - if (!cmd) - break; - - if (configMode) { - switch (cmd) { - case 0x40: { - uint8_t data[] = {0x5A, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5A}; - receiveAll(data, sizeof(data)); - break; - } - case 0x41: // check response data - if (analogEnabled == 1) { - // button pressures byte mask, appears after 0x44 is called - uint8_t data[] = {0x5A, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x5A}; - receiveAll(data, sizeof(data)); - } else { - uint8_t data[] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - receiveAll(data, sizeof(data)); - } - break; - case 0x42: { - uint8_t data[] = {0x5A, buttons1, buttons2}; - receiveAll(data, sizeof(data)); - break; - } - case 0x43: { // exit config mode - uint8_t data[] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - receiveAll(data, sizeof(data)); - if (data[1] == 0) { - configMode = 0; - } - break; - } - case 0x44: { // turn on analog mode - uint8_t data[] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - receiveAll(data, sizeof(data)); - param1 = data[1]; - if (param1 == 1) { - mode = 0x73; - analogEnabled = 1; - } else { - mode = 0x41; // no analog button pressures - analogEnabled = 0; - } - break; - } - case 0x45: { // query model - if (analogEnabled) { - uint8_t data[] = {0x5A, 0x01, 0x02, 0x01, 0x02, 0x01, 0x00}; - receiveAll(data, sizeof(data)); - } else { - uint8_t data[] = {0x5A, 0x01, 0x02, 0x00, 0x02, 0x01, 0x00}; - receiveAll(data, sizeof(data)); - } - break; - } - case 0x46: { - uint8_t data0[] = {0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0F}; - uint8_t data1[] = {0x5A, 0x00, 0x00, 0x01, 0x01, 0x01, 0x0F}; - receiveAll2(data0, data1, sizeof(data0)); - break; - } - case 0x47: { - uint8_t data[] = {0x5A, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}; - receiveAll(data, sizeof(data)); - break; - } - case 0x4C: { - uint8_t data0[] = {0x5A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00}; - uint8_t data1[] = {0x5A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00}; - receiveAll2(data0, data1, sizeof(data0)); - break; - } - case 0x4D: { // setup motors - uint8_t data[] = {0x5A, motorSetting1, motorSetting2, 0xFF, 0xFF, 0xFF, 0xFF}; - receiveAll(data, sizeof(data)); - motorSetting1 = data[1]; - motorSetting2 = data[2]; - break; - } - case 0x4F: { // set pressure byte mask, extended pressures - mode = 0x79; // analog button pressures - uint8_t data[] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A}; - receiveAll(data, sizeof(data)); - break; - } - } - while (!PS2_OUTPUT_ATT_READ()) { - sleep_us(20); // conservative so we aren't still in ATT low at the top of the loop - } - continue; - } else { - if (mode == 0x41) // digital only - { - uint8_t data[3] = {0x5A}; - memcpy(data, report, sizeof(data)); - // Buttons are inverted - data[1] ^= 0xFF; - data[2] ^= 0xFF; - receiveAll(data, sizeof(data)); - param1 = data[1]; - param2 = data[2]; - } - if (mode == 0x73) // digital buttons, analog joysticks - { - uint8_t data[7] = {0x5A}; - memcpy(data, report, sizeof(data)); - // Buttons are inverted - data[1] ^= 0xFF; - data[2] ^= 0xFF; - receiveAll(data, sizeof(data)); - param1 = data[1]; - } - if (mode == 0x79) // analog joysticks, analog buttons - { - uint8_t data[19] = {0x5A}; - memcpy(data, report, sizeof(data)); - // Buttons are inverted - data[1] ^= 0xFF; - data[2] ^= 0xFF; - receiveAll(data, sizeof(data)); - param1 = data[1]; - } - // cmd should usually be 0x42 for polling - if (cmd == 0x43) { - if (param1 == 0x01) { - configMode = 1; - while (!PS2_OUTPUT_ATT_READ()) { - sleep_us(20); // conservative so we aren't still in ATT low at the top of the loop - } - continue; - } - } - break; - } - } - PS2_OUTPUT_ACK_SET(); - - while (!PS2_OUTPUT_ATT_READ()) { - sleep_us(20); // conservative so we aren't still in ATT low at the top of the loop - } - return true; -} -#endif diff --git a/src/avr/shared/usb.cpp b/src/avr/shared/usb.cpp deleted file mode 100644 index 717020bed..000000000 --- a/src/avr/shared/usb.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "defines.h" -#if USB_HOST_STACK -void send_report_to_controller(uint8_t deviceType, const uint8_t *report, uint8_t len) { -} -USB_Device_Type_t get_device_address_for(uint8_t deviceType) { - return 0; -} -uint32_t transfer_with_usb_controller(const uint8_t dev_addr, const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t wLength, uint8_t *buffer, bool* status) { - return 0; -} -#endif -void authentication_successful() { -} \ No newline at end of file diff --git a/src/avr/uno/main/bootloader.c b/src/avr/uno/main/bootloader.c deleted file mode 100644 index 1707900e1..000000000 --- a/src/avr/uno/main/bootloader.c +++ /dev/null @@ -1,6 +0,0 @@ -void bootloader(void) { - // Handled by 8u2 / 16u2 -} -void reboot(void) { - // Handled by 8u2 / 16u2 -} \ No newline at end of file diff --git a/src/avr/uno/main/main.cpp b/src/avr/uno/main/main.cpp deleted file mode 100644 index 1ffcbd4e3..000000000 --- a/src/avr/uno/main/main.cpp +++ /dev/null @@ -1,266 +0,0 @@ -#include -#include -#include -#include -#include - -#include "Usb.h" -#include "commands.h" -#include "config.h" -#include "defines.h" -#include "descriptors.h" -#include "hid.h" -#include "packets.h" -#include "reports/controller_reports.h" -#include "shared_main.h" -#define INTERNAL_SERIAL_START_ADDRESS 0x0E -#define INTERNAL_SERIAL_LENGTH_BITS 80 -/** \name Control Request Data Direction Masks */ -/**@{*/ -/** Request data direction mask, indicating that the request data will flow from host to device. - * - * \see \ref CONTROL_REQTYPE_DIRECTION macro. - */ -#define REQDIR_HOSTTODEVICE (0 << 7) - -/** Request data direction mask, indicating that the request data will flow from device to host. - * - * \see \ref CONTROL_REQTYPE_DIRECTION macro. - */ -#define REQDIR_DEVICETOHOST (1 << 7) -typedef struct -{ - uint8_t Size; /**< Size of the descriptor, in bytes. */ - uint8_t Type; /**< Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value - * given by the specific class. - */ -} __attribute__((packed)) USB_Descriptor_Header_t; -typedef struct -{ - USB_Descriptor_Header_t Header; - uint16_t UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 4]; -} __attribute__((packed)) SignatureDescriptor_t; - -volatile uint16_t persistedConsoleType __attribute__((section(".noinit"))); -volatile uint16_t persistedConsoleTypeValid __attribute__((section(".noinit"))); -SignatureDescriptor_t signature; -// Set up some arrays for storing received data / data to transmit -uint8_t buf[255]; -uint8_t buf2[255]; - -// Flag for if we have received a packet that needs to be processed -volatile bool ready = false; - -// pointer to data to send, along with the length of the data remaining to send -uint8_t* bufTX; -uint8_t idxTX = 0; - -// Some reinterpretations of the data receive / send array, so we can easily read and write packets -packet_header_t* header = (packet_header_t*)buf; -descriptor_request_t* desc = (descriptor_request_t*)buf; -control_request_t* ctr = (control_request_t*)buf; -data_transmit_packet_t* dt = (data_transmit_packet_t*)buf; - -// If we have been ticked by usb for new data, then this will be true -bool has_previous_data = false; -uint8_t previous_data_len = 0; -// reset_usb is called by other parts of the code if we need to trigger a usb reload -// we just trigger a flag here, as we can send it on our next usb transfer -bool should_reload_usb = false; -bool usb_ready = false; - -static void USB_Device_GetInternalSerialDescriptor(void) { - signature.Header.Type = 0x03; - signature.Header.Size = sizeof(SignatureDescriptor_t); - - uint8_t CurrentGlobalInt = SREG; - cli(); - - uint8_t SigReadAddress = INTERNAL_SERIAL_START_ADDRESS; - - for (uint8_t SerialCharNum = 0; SerialCharNum < (INTERNAL_SERIAL_LENGTH_BITS / 4); SerialCharNum++) { - uint8_t SerialByte = boot_signature_byte_get(SigReadAddress); - - if (SerialCharNum & 0x01) { - SerialByte >>= 4; - SigReadAddress++; - } - - SerialByte &= 0x0F; - - signature.UnicodeString[SerialCharNum] = (SerialByte >= 10) ? (('A' - 10) + SerialByte) : ('0' + SerialByte); - } - - SREG = CurrentGlobalInt; - signature.UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4)] = '3'; - signature.UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 1] = consoleType + '0'; - -#if DEVICE_TYPE_IS_GAMEPAD - signature.UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 2] = DEVICE_TYPE + '0'; - signature.UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 3] = WINDOWS_USES_XINPUT + '0'; -#else - signature.UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 2] = 'K'; - signature.UnicodeString[(INTERNAL_SERIAL_LENGTH_BITS / 4) + 3] = '0'; -#endif -} - -void reset_usb(void) { - persistedConsoleType = consoleType; - persistedConsoleTypeValid = 0x3A2F; - should_reload_usb = true; - USB_Device_GetInternalSerialDescriptor(); -} - -bool usb_configured(void) { - return usb_ready; -} - -void setup() { - // Configure the UART for controller mode - UBRR0 = SERIAL_2X_UBBRVAL(BAUD); - UCSR0C = ((1 << UCSZ01) | (1 << UCSZ00)); - UCSR0A = (1 << U2X0); - UCSR0B = ((1 << TXEN0) | (1 << RXCIE0) | (1 << RXEN0)); - interrupts(); - - // Let the 8u2/16u2 know we are ready to receive data - UDR0 = READY; - init_main(); - if (persistedConsoleTypeValid == 0x3A2F) { - consoleType = persistedConsoleType; - } else { - consoleType = 0; - } - USB_Device_GetInternalSerialDescriptor(); -} -bool ready_for_next_packet() { - return !has_previous_data; -} -void send_report_to_pc(const void* report, uint8_t len) { - // Write the controller input data - memcpy(buf2, report, len); - previous_data_len = len; - has_previous_data = true; -} -void loop() { - // Wait for a packet from the 8u2/16u2. - if (!ready) { - if (!usb_ready) { - // tick controller when usb isn't ready for console bindings. - tick(); - } - return; - } - ready = false; - // Now handle the packet - switch (header->id) { - case USB_READY: - usb_ready = dt->data[0]; - return; - case CONTROLLER_DATA_TRANSMIT_ID: - // We received a hid out request, we need to process it - hid_set_report(dt->data, header->len - sizeof(packet_header_t), INTERRUPT_ID, INTERRUPT_ID); - header->len = 0; - break; - case CONTROLLER_DATA_REQUEST_ID: { - header->len = 0; - tick(); - if (has_previous_data) { - has_previous_data = false; - memcpy(buf + sizeof(packet_header_t), buf2, previous_data_len); - header->len = previous_data_len; - } - break; - } - case DESCRIPTOR_ID: { - // Wlength will be overwritten in descriptorRequest so cache it - uint16_t wLength = desc->wLength; - // 8u2/16u2 wants a descriptor, so return it - // Serial number string descriptor, return one we prepared earlier - if (desc->wValue == ((0x03 << 8) | 3)) { - memcpy(dt->data, &signature, sizeof(SignatureDescriptor_t)); - uint16_t len = sizeof(SignatureDescriptor_t); - if (len > wLength) len = wLength; - header->len = len; - break; - } - uint16_t len = descriptorRequest(desc->wValue, desc->wIndex, dt->data); - if (len > wLength) len = wLength; - header->len = len; - break; - } - case CONTROL_REQUEST_VALIDATION_ID: { - // 8u2/16u2 wants to know if we handle a descriptor, so let it know that - bool valid = controlRequestValid(ctr->bmRequestType, ctr->request, ctr->wValue, ctr->wIndex, ctr->wLength); - dt->data[0] = valid; - header->len = 1; - break; - } - case CONTROL_REQUEST_ID: { - // Wlength will be overwritten in descriptorRequest so cache it - uint16_t wLength = ctr->wLength; - // Some of our commands really need up to date data, so do another poll. - if (ctr->request >= COMMAND_REBOOT && ctr->request < MAX) { - tick(); - } - uint8_t* buf = dt->data; - if ((ctr->bmRequestType & REQDIR_DEVICETOHOST) == REQDIR_HOSTTODEVICE) { - buf = ctr->data; - } - // 8u2/16u2 wants us to handle a control request. - uint16_t len = controlRequest(ctr->bmRequestType, ctr->request, ctr->wValue, ctr->wIndex, ctr->wLength, buf, NULL); - if (len > wLength) len = wLength; - header->len = len; - break; - } - case DEVICE_ID: - usb_ready = true; - // 8u2/16u2 wants to know the console type, so return that - dt->data[0] = consoleType; - header->len = 1; - break; - default: - // unknown packet, do nothing - return; - } - // We are reloading usb, so instead of sending data back, let the 8u2/16u2 know we want usb reset - if (should_reload_usb) { - header->id = CONTROLLER_DATA_RESTART_USB_ID; - header->len = 0; - should_reload_usb = false; - } - // Send back any data in the buffers. enable the interrupt for pushing out data - bufTX = buf; - idxTX = header->len + sizeof(packet_header_t); - UCSR0B = (_BV(RXCIE0) | _BV(TXEN0) | _BV(RXEN0) | _BV(UDRIE0)); -} - -// Data receive interrupt -// Keep track of what we have read so far -uint8_t idx = 0; -ISR(USART_RX_vect, ISR_BLOCK) { - buf[idx] = UDR0; - // Wait for something that looks like the start of a packet - if (idx == 0 && buf[0] != VALID_PACKET) { - return; - } - // We found the start of a packet, so read the header and then use the length from that to read the entire packet into buf - idx++; - if (idx >= sizeof(packet_header_t) && header->len == idx) { - // We are done. reset for the next packet, and let the main loop know there is something to do - idx = 0; - ready = true; - return; - } -} - -// Data transmit interrupt -ISR(USART_UDRE_vect, ISR_BLOCK) { - if (idxTX--) { - // There is something to send still, so send that byte, and decrement the count of bytes - UDR0 = *(bufTX++); - } else { - // We are out of things to send, disable this interrupt - UCSR0B = (_BV(RXCIE0) | _BV(TXEN0) | _BV(RXEN0)); - } -} diff --git a/src/avr/uno/usb/main.c b/src/avr/uno/usb/main.c deleted file mode 100644 index c3254834d..000000000 --- a/src/avr/uno/usb/main.c +++ /dev/null @@ -1,658 +0,0 @@ -// This include needs to be at the top -#include "LUFAConfig.h" -// And then all others after it -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "commands.h" -#include "defines.h" -#include "endpoints.h" -#include "packets.h" -#include "progmem.h" -#include "serial_descriptors.h" -#include "serial_macros.h" -#define JUMP 0xDE00 - -/* USBtoUSART_WritePtr needs to be visible to ISR. */ -/* USARTtoUSB_ReadPtr needs to be visible to CDC LineEncoding Event. */ -volatile uint8_t USBtoUSART_WritePtr = 0; -volatile uint8_t USARTtoUSB_ReadPtr = 0; -static CDC_LineEncoding_t LineEncoding = {.BaudRateBPS = 0, - .CharFormat = CDC_LINEENCODING_OneStopBit, - .ParityType = CDC_PARITY_None, - .DataBits = 8}; - -// if bootloaderState is set to JUMP, then the arduino will jump to bootloader -// mode after the next watchdog reset -volatile uint16_t bootloaderState __attribute__((section(".noinit"))); -// Are we in usbserial mode or controller mode -bool serial = false; - -// Handle receiving data from the 328p during a control request -int handleControlRequest() { - register uint16_t tmp; - INIT_TMP_SERIAL_TO_USB(tmp); - uint8_t state = STATE_NO_PACKET; - uint8_t type; - uint8_t packetCount = 0; - while (true) { - WAIT_FOR_BYTES(tmp, 1); - register uint8_t data; - READ_BYTE_FROM_BUF(data, tmp); - // First we need to read out the packet header - if (state == STATE_NO_PACKET && data == VALID_PACKET) { - state = STATE_READ_PACKET_TYPE; - } else if (state == STATE_READ_PACKET_TYPE) { - type = data; - state = STATE_READ_LENGTH; - } else if (state == STATE_READ_LENGTH) { - if (type == CONTROL_REQUEST_VALIDATION_ID || type == DEVICE_ID) { - state = STATE_READ_AND_RETURN; - continue; - } - if (type == CONTROLLER_DATA_RESTART_USB_ID) { - // The 328p wants to restart the usb layer, so just reboot the microcontroller - bootloaderState = 0; - reboot(); - } - // For host to device requests, we don't have any more data to read as the host was writing the data - if ((USB_ControlRequest.bmRequestType & REQDIR_DEVICETOHOST) == REQDIR_HOSTTODEVICE) { - FINISH_READ(tmp); - return 0; - } - packetCount = data; - break; - } else if (state == STATE_READ_AND_RETURN) { - // We are done - FINISH_READ(tmp); - return data; - } - } - // Header is read, acknowledge the setup packet, and start writing bytes out from the circular buffer. - Endpoint_ClearSETUP(); - if (!packetCount) { - Endpoint_ClearIN(); - } - WAIT_FOR_BYTES(tmp, packetCount); - bool lastPacketFull = false; - while (packetCount || lastPacketFull) { - if (Endpoint_IsOUTReceived()) - break; - if (Endpoint_IsSETUPReceived()) - break; - - if (Endpoint_IsINReady()) { - uint16_t bytesInEndpoint = Endpoint_BytesInEndpoint(); - - while (packetCount && (bytesInEndpoint < USB_Device_ControlEndpointSize)) { - register uint8_t data; - READ_BYTE_FROM_BUF(data, tmp); - Endpoint_Write_8(data); - packetCount--; - bytesInEndpoint++; - } - - lastPacketFull = (bytesInEndpoint == USB_Device_ControlEndpointSize); - Endpoint_ClearIN(); - } - } - Endpoint_ClearStatusStage(); - // If the packet ends early, we still need to finish reading everything out of the buffer - while (packetCount--) { - register uint8_t data; - READ_BYTE_FROM_BUF(data, tmp); - } - FINISH_READ(tmp); - return 0; -} - -// Handle writing data for the controller endpoints (both in and out) -void handleControllerData() { - uint8_t txcount; - uint8_t type; - register uint16_t tmp; - uint8_t state = STATE_NO_PACKET; - INIT_TMP_SERIAL_TO_USB(tmp); - // Read the header - while (true) { - WAIT_FOR_BYTES(tmp, 1); - register uint8_t data; - READ_BYTE_FROM_BUF(data, tmp); - if (state == STATE_NO_PACKET && data == VALID_PACKET) { - state = STATE_READ_PACKET_TYPE; - } else if (state == STATE_READ_PACKET_TYPE) { - type = data; - state = STATE_READ_LENGTH; - } else if (state == STATE_READ_LENGTH) { - txcount = data; - // If the packet was host to device, than we are done here as the data was written already - if (type == CONTROLLER_DATA_TRANSMIT_ID) { - FINISH_READ(tmp); - // Acknowledge the packet - Endpoint_ClearOUT(); - return; - } - // If the packet is empty, stop - if (type == CONTROLLER_DATA_REQUEST_ID && !txcount) { - FINISH_READ(tmp); - return; - } - if (type == CONTROLLER_DATA_RESTART_USB_ID) { - reboot(); - } - break; - } - } - // This is device to host, so write out all the data to the endpoint - WAIT_FOR_BYTES(tmp, txcount); - while (txcount--) { - register uint8_t data; - READ_BYTE_FROM_BUF(data, tmp); - Endpoint_Write_8(data); - } - FINISH_READ(tmp); - // Acknowledge the packet - Endpoint_ClearIN(); -} -int main(void) { - // Handle jumping to different states depending on bootloaderState (which is preserved on a reboot) - if (bootloaderState == (JUMP | COMMAND_JUMP_BOOTLOADER)) { - // We don't want to jump again after the bootloader returns control flow to - // us - bootloaderState = 0; - asm volatile("jmp 0x1000"); - } - -#ifdef SERIAL_ONLY - serial = true; -#else - if (bootloaderState == (JUMP | COMMAND_JUMP_BOOTLOADER_UNO)) { - serial = true; - } -#endif - // We don't want to jump again after the bootloader returns control flow to - // us - bootloaderState = 0; - - /* Disable watchdog if enabled by bootloader/fuses */ - MCUSR &= ~(1 << WDRF); - wdt_disable(); - - clock_prescale_set(clock_div_1); - - // Configure the serial port for controller mode, usbserial mode will reconfigure it later - UCSR1C = ((1 << UCSZ11) | (1 << UCSZ10)); - UCSR1A = (1 << U2X1); - UCSR1B = ((1 << TXEN1) | (1 << RXEN1)); - UBRR1 = SERIAL_2X_UBBRVAL(BAUD); - - // Make sure that the 328p is fully reset, as it sends us the ready byte on bootup - AVR_RESET_LINE_DDR |= AVR_RESET_LINE_MASK; - AVR_RESET_LINE_PORT |= AVR_RESET_LINE_MASK; - _delay_ms(1); - AVR_RESET_LINE_PORT &= ~AVR_RESET_LINE_MASK; - _delay_ms(1); - AVR_RESET_LINE_PORT |= AVR_RESET_LINE_MASK; - - sei(); - if (serial) { - // Enable a timer to rapidly flush bytes over serial - TCCR0B = (1 << CS02); - } else { - // Wait for the 328p / 1280 to boot (we receive a READY byte) - // If we don't get it in time, we can assume the 328p is missing its firmware or has a wonky config and drop to the 328p programming mode - uint16_t count = 0; - uint8_t count2 = 0; - while (!(UCSR1A & (1 << RXC1)) || UDR1 != READY) { - count++; - if (count > 0xFFFE) { - count2++; - count = 0; - } - if (count2 > 0x2F) { - bootloaderState = (JUMP | COMMAND_JUMP_BOOTLOADER_UNO); - reboot(); - } - } - } - // Now that we have the ready byte above, we can turn on the serial receive interrupt handler - UCSR1B = ((1 << TXEN1) | (1 << RXCIE1) | (1 << RXEN1)); - - USB_Init(); - - // Loop for handling serial data - if (serial) { - while (true) { - USB_USBTask(); - // Send any data from the serial out buffer over USB - Endpoint_SelectEndpoint(DEVICE_EPADDR_IN); - if (Endpoint_IsINReady()) { - uint16_t tmp; - INIT_TMP_SERIAL_TO_USB(tmp); - uint8_t txcount; - uint8_t count = USARTtoUSB_WritePtr - USARTtoUSB_ReadPtr; - // Check if the UART receive buffer flush timer has expired or the buffer is nearly full - if (!((TIFR0 & (1 << TOV0)) || (count >= (SERIAL_TX_SIZE - 1)))) { - continue; - } - TIFR0 = (1 << TOV0); - txcount = SERIAL_TX_SIZE - 1; - if (txcount > count) { - txcount = count; - } - while (txcount--) { - register uint8_t data; - READ_BYTE_FROM_BUF(data, tmp); - Endpoint_Write_8(data); - } - // Save new pointer position - FINISH_READ(tmp); - Endpoint_ClearIN(); - } - - // Send any data received from usb to the serial in buffer - Endpoint_SelectEndpoint(DEVICE_EPADDR_OUT); - uint8_t countRX = 0; - if (Endpoint_IsOUTReceived()) { - // Check if we received any new bytes - countRX = Endpoint_BytesInEndpoint(); - - // Acknowledge zero length packet - if (!countRX) - Endpoint_ClearOUT(); - } - // Check if there is space for the data to receive - uint8_t USBtoUSART_free = (USB2USART_BUFLEN - 1) - ((USBtoUSART_WritePtr - USBtoUSART_ReadPtr) & (USB2USART_BUFLEN - 1)); - if (countRX && countRX <= USBtoUSART_free) { - // There is space, receive the data - uint16_t tmp; - INIT_TMP_USB_TO_SERIAL(tmp); - while (countRX--) { - register uint8_t data = Endpoint_Read_8(); - WRITE_BYTE_TO_BUF(data, tmp); - } - // Acknowledge the read - Endpoint_ClearOUT(); - FINISH_WRITE(tmp); - } - } - } - - // Controller mode, construct packets that we will need to send later - packet_header_t requestData = { - VALID_PACKET, CONTROLLER_DATA_REQUEST_ID, sizeof(packet_header_t)}; - packet_header_t tx_header = { - VALID_PACKET, CONTROLLER_DATA_TRANSMIT_ID, sizeof(packet_header_t)}; - - // Loop for handling controller mode - while (true) { - USB_USBTask(); - - // Check if the host is ready to receive a controller packet - Endpoint_SelectEndpoint(DEVICE_EPADDR_IN); - if (Endpoint_IsINReady()) { - // It is, request one from the 328p and then send it - uint16_t tmp; - INIT_TMP_USB_TO_SERIAL(tmp); - WRITE_ARRAY_TO_BUF(tmp, &requestData, sizeof(packet_header_t)); - - // Now wait for and process the response from the 328p - FINISH_WRITE(tmp); - handleControllerData(); - } - - // Check if the host has sent us a controller packet (for example, LEDs or other controller info) - Endpoint_SelectEndpoint(DEVICE_EPADDR_OUT); - if (Endpoint_IsOUTReceived()) { - // It has, send the packet to the 328p for processing - uint16_t tmp; - INIT_TMP_USB_TO_SERIAL(tmp); - uint8_t count = Endpoint_BytesInEndpoint(); - tx_header.len = sizeof(packet_header_t) + count; - WRITE_ARRAY_TO_BUF(tmp, &tx_header, sizeof(packet_header_t)); - // Check if the packet is empty or has data - if (Endpoint_IsReadWriteAllowed()) { - while (count--) { - register uint8_t data = Endpoint_Read_8(); - WRITE_BYTE_TO_BUF(data, tmp); - } - } - - // Now wait for and process the response from the 328p - FINISH_WRITE(tmp); - handleControllerData(); - } - } -} - -void write_ready(bool ready) { - uint16_t tmp; - INIT_TMP_USB_TO_SERIAL(tmp); - packet_header_t control_request_packet = {VALID_PACKET, USB_READY, sizeof(usb_ready_t)}; - WRITE_ARRAY_TO_BUF(tmp, &control_request_packet, sizeof(packet_header_t)); - WRITE_ARRAY_TO_BUF(tmp, &ready, 1); - FINISH_WRITE(tmp); -} - -void EVENT_USB_Device_Connect(void) { -} - -void EVENT_USB_Device_Disconnect(void) { - write_ready(false); -} - -void EVENT_USB_Device_ControlRequest(void) { - if (!(Endpoint_IsSETUPReceived())) return; - // Standard requests NEED to shortcut this system! - if ((USB_ControlRequest.bmRequestType & (REQTYPE_VENDOR | REQTYPE_CLASS)) == REQTYPE_STANDARD) { - return; - } - // Handle usbserial related control requests - if (serial) { - if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) { - if (USB_ControlRequest.bRequest == CDC_REQ_SetLineEncoding) { - Endpoint_ClearSETUP(); - - /* Read the line coding data in from the host into the global struct */ - Endpoint_Read_Control_Stream_LE(&LineEncoding, sizeof(CDC_LineEncoding_t)); - Endpoint_ClearIN(); - - // Handle the "1200bps touch" that pro micros use for jumping to the bootloader, only we reuse it here to jump to dfu moode - if (LineEncoding.BaudRateBPS == 1200) { - bootloaderState = (JUMP | COMMAND_JUMP_BOOTLOADER); - reboot(); - } else if (LineEncoding.BaudRateBPS == 2400) { - // And we have our own "2400bps touch" that just reboots, which will jump from usbserial back to controller mode - reboot(); - } - - /* Keep the TX line held high (idle) while the USART is reconfigured */ - PORTD |= (1 << 3); - - /* Flush data that was about to be sent. */ - USBtoUSART_ReadPtr = 0; - USBtoUSART_WritePtr = 0; - USARTtoUSB_ReadPtr = 0; - USARTtoUSB_WritePtr = 0; - - // Reconfigure the USART based on the LineEncoding - int8_t ConfigMask = 0; - - switch (LineEncoding.ParityType) { - case CDC_PARITY_Odd: - ConfigMask = ((1 << UPM11) | (1 << UPM10)); - break; - case CDC_PARITY_Even: - ConfigMask = (1 << UPM11); - break; - } - - if (LineEncoding.CharFormat == CDC_LINEENCODING_TwoStopBits) - ConfigMask |= (1 << USBS1); - - switch (LineEncoding.DataBits) { - case 6: - ConfigMask |= (1 << UCSZ10); - break; - case 7: - ConfigMask |= (1 << UCSZ11); - break; - case 8: - ConfigMask |= ((1 << UCSZ11) | (1 << UCSZ10)); - break; - } - - // Set the new baud rate before configuring the USART - uint8_t clockSpeed = (1 << U2X1); - uint16_t brr = SERIAL_2X_UBBRVAL(LineEncoding.BaudRateBPS); - - // No need U2X or cant have U2X. - if ((brr & 1) || (brr > 4095)) { - brr >>= 1; - clockSpeed = 0; - } - - // Or special case 57600 baud for compatibility with the ATmega328 bootloader. - else if (brr == SERIAL_2X_UBBRVAL(57600)) { - brr = SERIAL_UBBRVAL(57600); - clockSpeed = 0; - } - - UBRR1 = brr; - - // Reconfigure the USART - UCSR1C = ConfigMask; - UCSR1A = clockSpeed; - UCSR1B = ((1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1)); - - /* Release the TX line after the USART has been reconfigured */ - PORTD &= ~(1 << 3); - } else if (USB_ControlRequest.bRequest == CDC_REQ_SetControlLineState) { - Endpoint_ClearSETUP(); - Endpoint_ClearStatusStage(); - - // Handle the DTR line resetting the UNO, as the arduino uno uses this for programming - if (USB_ControlRequest.wValue & CDC_CONTROL_LINE_OUT_DTR) { - AVR_RESET_LINE_PORT &= ~AVR_RESET_LINE_MASK; - } else { - AVR_RESET_LINE_PORT |= AVR_RESET_LINE_MASK; - } - } - } else if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE) && USB_ControlRequest.bRequest == CDC_REQ_GetLineEncoding) { - // If the host requests the current line encoding return it - Endpoint_ClearSETUP(); - Endpoint_Write_Control_Stream_LE(&LineEncoding, sizeof(CDC_LineEncoding_t)); - Endpoint_ClearOUT(); - } - - return; - } - // Handle control requests for controller mode - // We uses a few control requests to jump between different modes on the uno, so handle that here - if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) { - if (USB_ControlRequest.bRequest >= COMMAND_REBOOT && USB_ControlRequest.bRequest <= COMMAND_JUMP_BOOTLOADER_UNO_USB_THEN_SERIAL) { - Endpoint_ClearSETUP(); - Endpoint_ClearStatusStage(); - // We cheat a little and use the commands for jumping as flags for when to jump to different modes - bootloaderState = (JUMP | USB_ControlRequest.bRequest); - reboot(); - } - } - - // Ask the 328p if wants to handle a control request, by sending it a validation header and the control request header - uint16_t tmp; - INIT_TMP_USB_TO_SERIAL(tmp); - packet_header_t control_request_packet = {VALID_PACKET, CONTROL_REQUEST_VALIDATION_ID, sizeof(control_request_t)}; - WRITE_ARRAY_TO_BUF(tmp, &control_request_packet, sizeof(packet_header_t)); - WRITE_ARRAY_TO_BUF(tmp, &USB_ControlRequest, sizeof(USB_ControlRequest)); - FINISH_WRITE(tmp); - if (!handleControlRequest()) { - // It does not want to handle the control request, return - return; - } - - // Handle the control request - control_request_packet.id = CONTROL_REQUEST_ID; - - // For host to device requests, we also send the data itself so increase the length - if ((USB_ControlRequest.bmRequestType & REQDIR_DEVICETOHOST) == REQDIR_HOSTTODEVICE) { - control_request_packet.len += USB_ControlRequest.wLength; - } - WRITE_ARRAY_TO_BUF(tmp, &control_request_packet, sizeof(packet_header_t)); - WRITE_ARRAY_TO_BUF(tmp, &USB_ControlRequest, sizeof(USB_ControlRequest)); - // For host to device requests, send the data from the host - if ((USB_ControlRequest.bmRequestType & REQDIR_DEVICETOHOST) == REQDIR_HOSTTODEVICE) { - Endpoint_ClearSETUP(); - uint8_t Length = USB_ControlRequest.wLength; - if (!(Length)) - Endpoint_ClearOUT(); - - while (Length) { - if (Endpoint_IsOUTReceived()) { - while (Length && Endpoint_BytesInEndpoint()) { - register uint8_t data = Endpoint_Read_8(); - WRITE_BYTE_TO_BUF(data, tmp); - Length--; - } - - Endpoint_ClearOUT(); - } - } - Endpoint_ClearStatusStage(); - } - - // Now wait for and process the response from the 328p. - FINISH_WRITE(tmp); - handleControlRequest(); -} -void EVENT_USB_Device_ConfigurationChanged(void) { - if (serial) { - // Configure endpoints for usbserial mode - Endpoint_ConfigureEndpoint(DEVICE_EPADDR_IN, EP_TYPE_BULK, SERIAL_TX_SIZE, 1); - Endpoint_ConfigureEndpoint(DEVICE_EPADDR_OUT, EP_TYPE_BULK, SERIAL_RX_SIZE, 1); - Endpoint_ConfigureEndpoint(CDC_NOTIFICATION, EP_TYPE_INTERRUPT, SERIAL_NOTIFICATION_SIZE, 1); - return; - } - // When in controller mode, we need to ask the 328p what type of controller we are emulating, so we can configure the endpoints correctly - uint16_t tmp; - INIT_TMP_USB_TO_SERIAL(tmp); - packet_header_t packet = { - VALID_PACKET, DEVICE_ID, sizeof(packet_header_t)}; - WRITE_ARRAY_TO_BUF(tmp, &packet, sizeof(packet_header_t)); - - // Now wait for and process the response from the 328p - FINISH_WRITE(tmp); - uint8_t consoleType = handleControlRequest(); - - // Now that we have the console type, we can configure the endpoints accordingly - uint8_t type = EP_TYPE_INTERRUPT; - uint8_t epsize = 0x20; - uint8_t epsizeOut = 0x08; - if (consoleType == WINDOWS || consoleType == XBOX360) { - epsizeOut = 0x20; - } - if (consoleType == MIDI_ID) { - type = EP_TYPE_BULK; - } - Endpoint_ConfigureEndpoint(DEVICE_EPADDR_IN, type, epsize, 2); - Endpoint_ConfigureEndpoint(DEVICE_EPADDR_OUT, type, epsizeOut, 2); - return; -} - -uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, - const uint16_t wIndex, - const void** const descriptorAddress) { - if (serial) { - // For usbserial mode, we have descriptors from "serial_descriptors.h" that we send - const uint8_t descriptorType = (wValue >> 8); - const void* address = NULL; - uint16_t size = 0; - - switch (descriptorType) { - case DTYPE_Device: - address = &usbSerialDeviceDescriptor; - size = sizeof(USB_Descriptor_Device_t); - break; - case DTYPE_Configuration: - address = &usbSerialConfigurationDescriptor; - size = sizeof(USB_Descriptor_Configuration_t); - break; - } - if (address) { - // To avoid needing to enable support for different descriptor areas - // we can write the descriptor outselves and act like we don't have a descriptor to write - Endpoint_ClearSETUP(); - Endpoint_Write_Control_PStream_LE(address, size); - Endpoint_ClearOUT(); - } - return 0; - } - // pass request to 328p / mega - descriptor_request_t packet = { - header : {VALID_PACKET, DESCRIPTOR_ID, sizeof(descriptor_request_t)}, - wValue : wValue, - wIndex : wIndex, - wLength : USB_ControlRequest.wLength - }; - uint16_t tmp; - INIT_TMP_USB_TO_SERIAL(tmp); - WRITE_ARRAY_TO_BUF(tmp, &packet, sizeof(descriptor_request_t)); - - // wait for a response from the 328p. At this point we can handle it exactly the same was as a control request - FINISH_WRITE(tmp); - handleControlRequest(); - return 0; -} - -/** ISR to manage the reception of data from the serial port, placing received - * bytes into a circular buffer for later transmission to the host. - */ -ISR(USART1_RX_vect, ISR_NAKED) { - // This ISR doesnt change SREG. Whoa. - asm volatile( - "lds r3, %[UDR1_Reg]\n\t" // (1) Load new Serial byte (UDR1) into r3 - "movw r4, r30\n\t" // (1) Backup Z pointer (r30 -> r4, r31 -> r5) - "in r30, %[writePointer]\n\t" // (1) Load USARTtoUSB write buffer 8 bit - // pointer to lower Z pointer - "ldi r31, 0x01\n\t" // (1) Set higher Z pointer to 0x01 - "st Z+, r3\n\t" // (2) Save UDR1 in Z pointer (USARTtoUSB write buffer) - // and increment - "out %[writePointer], r30\n\t" // (1) Save back new USARTtoUSB buffer - // pointer location - "movw r30, r4\n\t" // (1) Restore backuped Z pointer - "reti\n\t" // (4) Exit ISR - - // Inputs: - ::[UDR1_Reg] "m"(UDR1), // Memory location of UDR1 - [writePointer] "I"(_SFR_IO_ADDR( - USARTtoUSB_WritePtr)) // 8 bit pointer to USARTtoUSB write buffer - ); -} - -ISR(USART1_UDRE_vect, ISR_NAKED) { - // Another SREG-less ISR. - asm volatile( - "movw r4, r30\n\t" // (1) Backup Z pointer (r30 -> r4, r31 -> r5) - "in r30, %[readPointer]\n\t" // (1) Load USBtoUSART read buffer 8 bit - // pointer to lower Z pointer - "ldi r31, 0x02\n\t" // (1) Set higher Z pointer to 0x02 - "ld r3, Z+\n\t" // (2) Load next byte from USBtoUSART buffer into r3 - "sts %[UDR1_Reg], r3\n\t" // (2) Save r3 (next byte) in UDR1 - "out %[readPointer], r30\n\t" // (1) Save back new USBtoUSART read - // buffer pointer location - "cbi %[readPointer], 7\n\t" // (2) Wrap around for 128 bytes - // smart after-the-fact andi 0x7F without using SREG - "movw r30, r4\n\t" // (1) Restore backuped Z pointer - "in r2, %[readPointer]\n\t" // (1) Load USBtoUSART read buffer 8 bit - // pointer to r2 - "lds r3, %[writePointer]\n\t" // (1) Load USBtoUSART write buffer to r3 - "cpse r2, r3\n\t" // (1/2) Check if USBtoUSART read buffer == USBtoUSART - // write buffer - "reti\n\t" // (4) They are not equal, more bytes coming soon! - "ldi r30, 0x98\n\t" // (1) Set r30 temporary to new UCSR1B setting - // ((1< -#include "progmem.h" -#include "endpoints.h" - -typedef struct -{ - USB_Descriptor_Configuration_Header_t Config; - USB_Descriptor_Interface_t CDC_CCI_Interface; - USB_CDC_Descriptor_FunctionalHeader_t CDC_Functional_Header; - USB_CDC_Descriptor_FunctionalACM_t CDC_Functional_ACM; - USB_CDC_Descriptor_FunctionalUnion_t CDC_Functional_Union; - USB_Descriptor_Endpoint_t CDC_NotificationEndpoint; - USB_Descriptor_Interface_t CDC_DCI_Interface; - USB_Descriptor_Endpoint_t CDC_DataOutEndpoint; - USB_Descriptor_Endpoint_t CDC_DataInEndpoint; -} USB_Descriptor_Configuration_t; - -extern const USB_Descriptor_Device_t usbSerialDeviceDescriptor; - -extern const USB_Descriptor_Configuration_t usbSerialConfigurationDescriptor; \ No newline at end of file diff --git a/src/avr/uno/usb/serial_macros.h b/src/avr/uno/usb/serial_macros.h deleted file mode 100644 index 039f19b7e..000000000 --- a/src/avr/uno/usb/serial_macros.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once -#include - -#define USBtoUSART_ReadPtr GPIOR0 // to use cbi() -#define USARTtoUSB_WritePtr GPIOR1 - -extern volatile uint8_t USBtoUSART_WritePtr; -extern volatile uint8_t USARTtoUSB_ReadPtr; - -#define USART2USB_BUFLEN 256 // 0xFF - 8bit -#define USB2USART_BUFLEN 128 // 0x7F - 7bit - -// A collection of asm snippets that get reused everywhere, so they are made into macros - -#define INIT_TMP_SERIAL_TO_USB(tmp_ptr) \ - asm( \ - "lds %A[tmp], %[readPtr]\n\t" /* (1) Copy read pointer into lower byte*/ /* Outputs */ \ - : [tmp] "=&e"(tmp_ptr) /* Pointer register, output only*/ /* Inputs */ \ - : [readPtr] "m"(USARTtoUSB_ReadPtr) /* Memory location */ \ - ) - -#define READ_BYTE_FROM_BUF(data_ptr, tmp_ptr) \ - asm( \ - "ldi %B[tmp] , 0x01\n\t" /* (1) Force high byte to 0x01 */ \ - "ld %[data] , %a[tmp] +\n\t" /* (2) Load next data byte, wraps around 255 */ /* Outputs */ \ - : [data] "=&r"(data_ptr), /* Output only */ \ - [tmp] "=e"(tmp_ptr) /* Input and output */ /* Inputs */ \ - : "1"(tmp_ptr)) - -#define INIT_TMP_USB_TO_SERIAL(tmp_ptr) \ - asm( \ - "ldi %B[tmp], 0x02\n\t" /* (1) Force high byte to 0x200 */ \ - "lds %A[tmp], %[writePtr]\n\t" /* (1) Load USBtoUSART_WritePtr into low byte */ /* Outputs */ \ - : [tmp] "=&e"(tmp_ptr) /* Pointer register, output only*/ /* Inputs */ \ - : [writePtr] "m"(USBtoUSART_WritePtr) /* Memory location */ \ - ) - -#define WRITE_BYTE_TO_BUF(data_ptr, tmp_ptr) \ - asm( \ - "st %a[tmp]+, %[data]\n\t" /* (2) Save byte in buffer and increment */ \ - "andi %A[tmp], 0x7F\n\t" /* (1) wrap around pointer, 128 bytes */ /* Outputs */ \ - : [tmp] "=e"(tmp_ptr) /* Input and output */ /* Inputs */ \ - : "0"(tmp_ptr), \ - [data] "r"(data_ptr)) - -#define WRITE_ARRAY_TO_BUF(tmp_ptr, buf_ptr, length) \ - { \ - uint8_t len = length; \ - uint8_t* buf = (uint8_t*)buf_ptr; \ - do { \ - register uint8_t data; \ - data = *(buf++); \ - WRITE_BYTE_TO_BUF(data, tmp_ptr); \ - } while (--len); \ - } - -#define FINISH_WRITE(tmp_ptr) \ - USBtoUSART_WritePtr = tmp_ptr & 0xFF; \ - UCSR1B = (_BV(RXCIE1) | _BV(TXEN1) | _BV(RXEN1) | _BV(UDRIE1)) - -#define FINISH_READ(tmp_ptr) \ - USARTtoUSB_ReadPtr = tmp_ptr & 0xFF - -#define WAIT_FOR_BYTES(tmp_ptr, n) \ - while (((USARTtoUSB_WritePtr - tmp_ptr) & 0xFF) < n) { \ - } diff --git a/src/pico/TUSB-MIDI.hpp b/src/pico/TUSB-MIDI.hpp deleted file mode 100644 index 3ef11a674..000000000 --- a/src/pico/TUSB-MIDI.hpp +++ /dev/null @@ -1,198 +0,0 @@ -#pragma once - -#include -#include -#include "TUSB-MIDI_defs.hpp" -#include "tusb.h" - -namespace usbMidi { - - class UsbMidiTransport { - private: - byte mTxBuffer[4]; - size_t mTxIndex; - MidiType mTxStatus; - - byte mRxBuffer[4]; - size_t mRxLength; - size_t mRxIndex; - - midiEventPacket_t mPacket; - uint8_t cableNumber; - - static const size_t MIDI_QUEUE_SIZE = 16; - midiEventPacket_t midiQueue[MIDI_QUEUE_SIZE] = {{0}}; - size_t midiQueueIndex = 0; - - public: - UsbMidiTransport(uint8_t cableNumber = 0) { - this->cableNumber = cableNumber; - }; - - public: - uint8_t midi_dev_addr = 0; - - static const bool thruActivated = false; - - void begin() { - mTxIndex = 0; - mRxIndex = 0; - mRxLength = 0; - }; - - void pollUsb() { - if (!midi_dev_addr || !tuh_midi_configured(midi_dev_addr)) { - return; - } - if (tuh_midih_get_num_rx_cables(midi_dev_addr) < 1) { - return; - } - - tuh_midi_read_poll(midi_dev_addr); // if there is data, then the callback will be called - tuh_midi_stream_flush(midi_dev_addr); - } - - void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets) { - if (midi_dev_addr != dev_addr) return; - - while (num_packets > 0) { - --num_packets; - uint8_t bytes[4]; - if (tuh_midi_packet_read(dev_addr, bytes)) { - TU_LOG1("Read bytes %u %u %u %u\r\n", bytes[0], bytes[1], bytes[2], bytes[3]); - - midiEventPacket_t packet = { - .header = bytes[0], - .byte1 = bytes[1], - .byte2 = bytes[2], - .byte3 = bytes[3] - }; - - if(midiQueueIndex < MIDI_QUEUE_SIZE - 1) { - midiQueue[midiQueueIndex] = packet; - midiQueueIndex++; - } else { - TU_LOG1("Buffer overflow"); - } - } - } - } - - void end() { - } - - bool beginTransmission(MidiType status) { - mTxStatus = status; - - byte cin = 0; - if (status < SystemExclusive) { - // Non System messages - cin = type2cin[((status & 0xF0) >> 4) - 7][1]; - mPacket.header = MAKEHEADER(cableNumber, cin); - } else { - // Only System messages - cin = system2cin[status & 0x0F][1]; - mPacket.header = MAKEHEADER(cableNumber, cin); - } - - mPacket.byte1 = mPacket.byte2 = mPacket.byte3 = 0; - mTxIndex = 0; - - return true; - }; - - void write(byte byte) { - if (mTxStatus != MidiType::SystemExclusive) { - if (mTxIndex == 0) mPacket.byte1 = byte; - else if (mTxIndex == 1) mPacket.byte2 = byte; - else if (mTxIndex == 2) mPacket.byte3 = byte; - } else if (byte == MidiType::SystemExclusiveStart) { - mPacket.header = MAKEHEADER(cableNumber, 0x04); - mPacket.byte1 = byte; - } else // SystemExclusiveEnd or SysEx data - { - auto i = mTxIndex % 3; - if (byte == MidiType::SystemExclusiveEnd) - mPacket.header = MAKEHEADER(cableNumber, (0x05 + i)); - - if (i == 0) { - mPacket.byte1 = byte; - mPacket.byte2 = mPacket.byte3 = 0x00; - } else if (i == 1) { - mPacket.byte2 = byte; - mPacket.byte3 = 0x00; - } else if (i == 2) { - mPacket.byte3 = byte; - if (byte != MidiType::SystemExclusiveEnd) { - tuh_midi_packet_write(midi_dev_addr, (uint8_t*)&mPacket); - } - } - } - mTxIndex++; - }; - - void endTransmission() { - tuh_midi_packet_write(midi_dev_addr, (uint8_t*)&mPacket); - }; - - byte read() { - RXBUFFER_POPFRONT(byte); - return byte; - }; - - unsigned available() { - // consume mRxBuffer first, before getting a new packet - if (mRxLength > 0) - return mRxLength; - - mRxIndex = 0; - if(midiQueueIndex > 0) { - mPacket = midiQueue[midiQueueIndex - 1]; - midiQueueIndex--; - } else { - pollUsb(); - mPacket.header = 0; - } - - if (mPacket.header != 0) { - auto cn = GETCABLENUMBER(mPacket); - if (cn != cableNumber) - return 0; - - auto cin = GETCIN(mPacket); - auto len = cin2Len[cin][1]; - switch (len) { - case 0: - if (cin == 0x4 || cin == 0x7) RXBUFFER_PUSHBACK3 - else if (cin == 0x5) RXBUFFER_PUSHBACK1 - else if (cin == 0x6) RXBUFFER_PUSHBACK2 - break; - case 1: RXBUFFER_PUSHBACK1 - break; - case 2: RXBUFFER_PUSHBACK2 - break; - case 3: RXBUFFER_PUSHBACK3 - break; - default: - break; // error - } - } - - return mRxLength; - }; - }; - -} - -/*! \brief - */ -#define USBMIDI_CREATE_INSTANCE(CableNr, Name) \ - USBMIDI_NAMESPACE::usbMidiTransport __usb##Name(CableNr);\ - MIDI_NAMESPACE::MidiInterface Name((USBMIDI_NAMESPACE::usbMidiTransport&)__usb##Name); - -#define USBMIDI_CREATE_CUSTOM_INSTANCE(CableNr, Name, Settings) \ - USBMIDI_NAMESPACE::usbMidiTransport __usb##Name(CableNr);\ - MIDI_NAMESPACE::MidiInterface Name((USBMIDI_NAMESPACE::usbMidiTransport&)__usb##Name); - -#define USBMIDI_CREATE_DEFAULT_INSTANCE() \ - USBMIDI_CREATE_INSTANCE(0, MIDI) diff --git a/src/pico/TUSB-MIDI_defs.hpp b/src/pico/TUSB-MIDI_defs.hpp deleted file mode 100644 index 019900487..000000000 --- a/src/pico/TUSB-MIDI_defs.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include - -namespace usbMidi { - - using namespace MIDI_NAMESPACE; - -// from https://www.usb.org/sites/default/files/midi10.pdf -// 4 USB-MIDI Event Packets -// Table 4-1: Code Index Number Classifications - - static uint8_t type2cin[][2] = { {MidiType::InvalidType,0}, {MidiType::NoteOff,8}, {MidiType::NoteOn,9}, {MidiType::AfterTouchPoly,0xA}, {MidiType::ControlChange,0xB}, {MidiType::ProgramChange,0xC}, {MidiType::AfterTouchChannel,0xD}, {MidiType::PitchBend,0xE} }; - - static uint8_t system2cin[][2] = { {MidiType::SystemExclusive,0}, {MidiType::TimeCodeQuarterFrame,2}, {MidiType::SongPosition,3}, {MidiType::SongSelect,2}, {0,0}, {0,0}, {MidiType::TuneRequest,5}, {MidiType::SystemExclusiveEnd,0}, {MidiType::Clock,0xF}, {0,0}, {MidiType::Start,0xF}, {MidiType::Continue,0xF}, {MidiType::Stop,0xF}, {0,0}, {MidiType::ActiveSensing,0xF}, {MidiType::SystemReset,0xF} }; - - static uint8_t cin2Len[][2] = { {0,0}, {1,0}, {2,2}, {3,3}, {4,0}, {5,0}, {6,0}, {7,0}, {8,3}, {9,3}, {10,3}, {11,3}, {12,2}, {13,2}, {14,3}, {15,1} }; - -#define GETCABLENUMBER(packet) (packet.header >> 4); -#define GETCIN(packet) (packet.header & 0x0f); -#define MAKEHEADER(cn, cin) (((cn & 0x0f) << 4) | cin) -#define RXBUFFER_PUSHBACK1 { mRxBuffer[mRxLength++] = mPacket.byte1; } -#define RXBUFFER_PUSHBACK2 { mRxBuffer[mRxLength++] = mPacket.byte1; mRxBuffer[mRxLength++] = mPacket.byte2; } -#define RXBUFFER_PUSHBACK3 { mRxBuffer[mRxLength++] = mPacket.byte1; mRxBuffer[mRxLength++] = mPacket.byte2; mRxBuffer[mRxLength++] = mPacket.byte3; } -#define RXBUFFER_POPFRONT(byte) auto byte = mRxBuffer[mRxIndex++]; mRxLength--; -//#define SENDMIDI(packet) { MidiUSB.sendMIDI(packet); MidiUSB.flush(); } - -} - -typedef struct -{ - uint8_t header; - uint8_t byte1; - uint8_t byte2; - uint8_t byte3; -} midiEventPacket_t; \ No newline at end of file diff --git a/src/pico/bt.cpp b/src/pico/bt.cpp index 4d837d9df..cb29d91b2 100644 --- a/src/pico/bt.cpp +++ b/src/pico/bt.cpp @@ -184,6 +184,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe switch (hci_event_packet_get_type(packet)) { case HCI_EVENT_DISCONNECTION_COMPLETE: con_handle = HCI_CON_HANDLE_INVALID; + reset_player_leds(); printf("Disconnected\r\n"); break; case SM_EVENT_JUST_WORKS_REQUEST: @@ -282,6 +283,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe } int btstack_main(void); + int btstack_main(void) { printf("Bt tx init\r\n"); le_keyboard_setup(); diff --git a/src/pico/bt_rx.cpp b/src/pico/bt_rx.cpp index 8ba97bbd1..9e2ca6fcc 100644 --- a/src/pico/bt_rx.cpp +++ b/src/pico/bt_rx.cpp @@ -20,11 +20,13 @@ #include "hid.h" #include "hidparser.h" #include "shared_main.h" +#include "hci_dump_embedded_stdout.h" // TAG to store remote device address and type in TLV #define TLV_TAG_HOGD ((((uint32_t)'H') << 24) | (((uint32_t)'O') << 16) | (((uint32_t)'G') << 8) | 'D') -typedef struct { +typedef struct +{ bd_addr_t addr; bd_addr_type_t addr_type; } le_device_addr_t; @@ -63,6 +65,9 @@ static uint8_t hid_descriptor_storage[500]; static uint8_t send_report_buf[64]; static uint8_t send_report_len = 0; +// Set up simulated GATTSERVICE_SUBEVENT_HID_SERVICE_REPORTS_NOTIFICATION +static bool reports_notif_pending = false; + // used to implement connection timeout and reconnect timer static btstack_timer_source_t connection_timer; static btstack_timer_source_t reconnect_timer; @@ -84,13 +89,15 @@ static void hog_connect(void); * @param size * @returns true if it does */ -static bool adv_event_contains_hid_service(const uint8_t *packet) { +static bool adv_event_contains_hid_service(const uint8_t *packet) +{ const uint8_t *ad_data = gap_event_advertising_report_get_data(packet); uint8_t ad_len = gap_event_advertising_report_get_data_length(packet); return ad_data_contains_uuid16(ad_len, ad_data, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE); } -typedef struct { +typedef struct +{ char addr[SIZE_OF_BD_ADDRESS]; char name_buffer[100]; } scan_data_t; @@ -99,28 +106,34 @@ static scan_data_t devices[MAX_DEVICES_TO_SCAN]; static uint16_t buffer_size; static uint8_t devices_found; -int get_bt_address(uint8_t *addr) { +int get_bt_address(uint8_t *addr) +{ bd_addr_t local_addr; gap_local_bd_addr(local_addr); memcpy(addr, bd_addr_to_str(local_addr), SIZE_OF_BD_ADDRESS); return SIZE_OF_BD_ADDRESS; } -void bt_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_t report_id) { - hids_client_send_write_report(hids_cid, 1, HID_REPORT_TYPE_OUTPUT, send_report_buf, send_report_len); +void bt_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_t report_id) +{ memcpy(send_report_buf, data, len); send_report_len = len; + // Reorder to after memcopy so that reports get properly flushed, needed for 360. + hids_host_send_write_report(hids_cid, 1, HID_REPORT_TYPE_OUTPUT, send_report_buf, send_report_len); } -bool check_bluetooth_ready() { +bool check_bluetooth_ready() +{ return app_state == READY; } -void bt_stop_scan() { +void bt_stop_scan() +{ gap_stop_scan(); } -static void bt_stop_scan_timer(btstack_timer_source_t *ts) { +static void bt_stop_scan_timer(btstack_timer_source_t *ts) +{ UNUSED(ts); printf("stop scan\r\n"); gap_stop_scan(); @@ -128,17 +141,19 @@ static void bt_stop_scan_timer(btstack_timer_source_t *ts) { /** * Start scanning */ -void bt_start_scan() { +void bt_start_scan() +{ printf("Scanning for LE HID devices...\r\n"); devices_found = 0; #ifdef BT_ADDR - if (has_address) { + if (has_address) + { strcpy(devices[0].name_buffer, bt_addr); devices_found = 1; } #endif // Passive scanning, 100% (scan interval = scan window) - gap_set_scan_parameters(0, 48, 48); + gap_set_scan_parameters(1, 48, 48); gap_start_scan(); // Auto stop scanning after 10 seconds btstack_run_loop_set_timer(&scan_timer, 10000); @@ -146,9 +161,11 @@ void bt_start_scan() { btstack_run_loop_add_timer(&scan_timer); } -int bt_get_scan_results(uint8_t *buf) { +int bt_get_scan_results(uint8_t *buf) +{ int size = 0; - for (int i = 0; i < devices_found; i++) { + for (int i = 0; i < devices_found; i++) + { int len = strnlen(devices[i].name_buffer, sizeof(devices[i].name_buffer)); memcpy(buf + size, devices[i].name_buffer, len); size += len; @@ -162,7 +179,8 @@ int bt_get_scan_results(uint8_t *buf) { * Handle timer event to trigger reconnect * @param ts */ -static void hog_reconnect_timeout(btstack_timer_source_t *ts) { +static void hog_reconnect_timeout(btstack_timer_source_t *ts) +{ UNUSED(ts); hog_connect(); } @@ -170,7 +188,8 @@ static void hog_reconnect_timeout(btstack_timer_source_t *ts) { * Handle timeout for outgoing connection * @param ts */ -static void hog_connection_timeout(btstack_timer_source_t *ts) { +static void hog_connection_timeout(btstack_timer_source_t *ts) +{ UNUSED(ts); printf("Timeout - abort connection\r\n"); gap_connect_cancel(); @@ -183,7 +202,8 @@ static void hog_connection_timeout(btstack_timer_source_t *ts) { /** * Connect to remote device but set timer for timeout */ -static void hog_connect(void) { +static void hog_connect(void) +{ // set timer btstack_run_loop_set_timer(&connection_timer, 10000); btstack_run_loop_set_timer_handler(&connection_timer, &hog_connection_timeout); @@ -192,7 +212,8 @@ static void hog_connect(void) { gap_connect(remote_device.addr, remote_device.addr_type); } -static void hog_start_reconnect_timer() { +static void hog_start_reconnect_timer() +{ btstack_run_loop_set_timer(&connection_timer, 100); btstack_run_loop_set_timer_handler(&connection_timer, &hog_reconnect_timeout); btstack_run_loop_add_timer(&connection_timer); @@ -201,8 +222,10 @@ static void hog_start_reconnect_timer() { /** * Start connecting after boot up: connect to last used device if possible, start scan otherwise */ -static void hog_start_connect(void) { - if (has_address) { +static void hog_start_connect(void) +{ + if (has_address) + { } // Only try to connect if we have "paired" a device #ifdef BT_ADDR @@ -213,7 +236,8 @@ static void hog_start_connect(void) { /** * In case of error, disconnect and start scanning again */ -static void handle_outgoing_connection_error(void) { +static void handle_outgoing_connection_error(void) +{ printf("Error occurred, disconnect and start over\r\n"); gap_disconnect(connection_handle); hog_start_reconnect_timer(); @@ -226,206 +250,318 @@ static void handle_outgoing_connection_error(void) { * @param packet * @param size */ -static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { +static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) +{ UNUSED(packet_type); UNUSED(channel); UNUSED(size); uint8_t status; - if (hci_event_packet_get_type(packet) != HCI_EVENT_GATTSERVICE_META) { + if (hci_event_packet_get_type(packet) != HCI_EVENT_GATTSERVICE_META) + { return; } - switch (hci_event_gattservice_meta_get_subevent_code(packet)) { - case GATTSERVICE_SUBEVENT_HID_SERVICE_CONNECTED: - status = gattservice_subevent_hid_service_connected_get_status(packet); - switch (status) { - case ERROR_CODE_SUCCESS: - printf("HID service client connected, found %d services\r\n", - gattservice_subevent_hid_service_connected_get_num_instances(packet)); - - // store device as bonded - if (btstack_tlv_singleton_impl) { - btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, TLV_TAG_HOGD, (const uint8_t *)&remote_device, sizeof(remote_device)); - } - - hids_client_get_hid_information(hids_cid, 0); - // done - printf("Ready - receiving data\r\n"); - app_state = READY; - bluetooth_connected(); - break; - default: - printf("HID service client connection failed, err 0x%02x.\r\n", status); - handle_outgoing_connection_error(); - break; + switch (hci_event_gattservice_meta_get_subevent_code(packet)) + { + case GATTSERVICE_SUBEVENT_HID_SERVICE_CONNECTED: + status = gattservice_subevent_hid_service_connected_get_status(packet); + switch (status) + { + case ERROR_CODE_SUCCESS: + printf("HID service client connected, found %d services\r\n", + gattservice_subevent_hid_service_connected_get_num_instances(packet)); + + // store device as bonded + if (btstack_tlv_singleton_impl) + { + btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, TLV_TAG_HOGD, (const uint8_t *)&remote_device, sizeof(remote_device)); } + + hids_host_get_hid_information(hids_cid, 0); + // done + printf("Ready - receiving data\r\n"); + app_state = READY; + bluetooth_connected(); break; - case GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_PNP_ID: - status = gattservice_subevent_device_information_pnp_id_get_att_status(packet); - if (status != ATT_ERROR_SUCCESS) { - printf("PNP ID read failed, ATT Error 0x%02x\n", status); - } else { - vid = gattservice_subevent_device_information_pnp_id_get_vendor_id(packet); - pid = gattservice_subevent_device_information_pnp_id_get_product_id(packet); - version = gattservice_subevent_device_information_pnp_id_get_product_version(packet); - type.console_type = GENERIC; - get_usb_device_type_for(vid, pid, version, &type); - printf("Vendor Source ID: 0x%02x\r\n", gattservice_subevent_device_information_pnp_id_get_vendor_source_id(packet)); - printf("Vendor ID: 0x%04x\r\n", gattservice_subevent_device_information_pnp_id_get_vendor_id(packet)); - printf("Product ID: 0x%04x\r\n", gattservice_subevent_device_information_pnp_id_get_product_id(packet)); - printf("Product Version: 0x%04x\r\n", gattservice_subevent_device_information_pnp_id_get_product_version(packet)); - } + default: + printf("HID service client connection failed, err 0x%02x.\r\n", status); + handle_outgoing_connection_error(); break; - case GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE: - printf("info done\r\n"); - // TODO: do other controllers work okay with this? - if (type.console_type == SANTROLLER) { - gap_update_connection_parameters(connection_handle, 6, 6, 0, 100); + } + break; + case GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_PNP_ID: + status = gattservice_subevent_device_information_pnp_id_get_att_status(packet); + if (status != ATT_ERROR_SUCCESS) + { + printf("PNP ID read failed, ATT Error 0x%02x\n", status); + } + else + { + vid = gattservice_subevent_device_information_pnp_id_get_vendor_id(packet); + pid = gattservice_subevent_device_information_pnp_id_get_product_id(packet); + version = gattservice_subevent_device_information_pnp_id_get_product_version(packet); + type.console_type = GENERIC; + get_usb_device_type_for(vid, pid, version, &type); + printf("Vendor Source ID: 0x%02x\r\n", gattservice_subevent_device_information_pnp_id_get_vendor_source_id(packet)); + printf("Vendor ID: 0x%04x\r\n", gattservice_subevent_device_information_pnp_id_get_vendor_id(packet)); + printf("Product ID: 0x%04x\r\n", gattservice_subevent_device_information_pnp_id_get_product_id(packet)); + printf("Product Version: 0x%04x\r\n", gattservice_subevent_device_information_pnp_id_get_product_version(packet)); + } + break; + case GATTSERVICE_SUBEVENT_DEVICE_INFORMATION_DONE: + printf("info done\r\n"); + // TODO: do other controllers work okay with this? + if (type.console_type == SANTROLLER) + { + gap_update_connection_parameters(connection_handle, 6, 6, 0, 100); + } + hids_host_connect(connection_handle, handle_gatt_client_event, protocol_mode, &hids_cid); + break; + case GATTSERVICE_SUBEVENT_HID_INFORMATION: + { + uint16_t cid = gattservice_subevent_hid_information_get_hids_cid(packet); + if (type.console_type == GENERIC) + { + foundPS3 = false; + foundPS4 = false; + foundPS5 = false; + USB_ProcessHIDReport(hids_host_descriptor_storage_get_descriptor_data(cid, 0), hids_host_descriptor_storage_get_descriptor_len(cid, 0), &info); + + if (foundPS5) + { + type.console_type = PS5; } - hids_client_connect(connection_handle, handle_gatt_client_event, protocol_mode, &hids_cid); - break; - case GATTSERVICE_SUBEVENT_HID_INFORMATION: { - uint16_t cid = gattservice_subevent_hid_information_get_hids_cid(packet); - if (type.console_type == GENERIC) { - foundPS3 = false; - foundPS4 = false; - foundPS5 = false; - USB_ProcessHIDReport(hids_client_descriptor_storage_get_descriptor_data(cid, 0), hids_client_descriptor_storage_get_descriptor_len(cid, 0), &info); - - if (foundPS5) { - type.console_type = PS5; - } - if (foundPS4) { - type.console_type = PS4; - } - if (foundPS3) { - type.console_type = PS3; - } + if (foundPS4) + { + type.console_type = PS4; } - break; - } - case GATTSERVICE_SUBEVENT_HID_REPORT: { - if (type.console_type == GENERIC) { - fill_generic_report(info, gattservice_subevent_hid_report_get_report(packet), &bt_data); - break; + if (foundPS3) + { + type.console_type = PS3; } - tick_bluetooth(gattservice_subevent_hid_report_get_report(packet), gattservice_subevent_hid_report_get_report_len(packet), type); + } + reports_notif_pending = true; + break; + } + case GATTSERVICE_SUBEVENT_HID_REPORT: + { + // On first report after connection, send Player IDs + if (reports_notif_pending && current_player != 0xFF) { + reports_notif_pending = false; + send_player_leds_bt(); + } + if (type.console_type == GENERIC) + { + fill_generic_report(info, gattservice_subevent_hid_report_get_report(packet), &bt_data); break; } + tick_bluetooth(gattservice_subevent_hid_report_get_report(packet), gattservice_subevent_hid_report_get_report_len(packet), type); + break; + } - default: - break; + default: + break; } } - /* LISTING_START(packetHandler): Packet Handler */ -static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) +{ /* LISTING_PAUSE */ UNUSED(channel); UNUSED(size); uint8_t event; /* LISTING_RESUME */ - switch (packet_type) { - case HCI_EVENT_PACKET: - event = hci_event_packet_get_type(packet); - switch (event) { - case BTSTACK_EVENT_STATE: - if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break; - btstack_assert(app_state == W4_WORKING); - - hog_start_connect(); - break; - case GAP_EVENT_ADVERTISING_REPORT: { - if (adv_event_contains_hid_service(packet) == false) break; - // store remote device address and type - bd_addr_t address; - gap_event_advertising_report_get_address(packet, address); - const uint8_t *adv_data = gap_event_advertising_report_get_data(packet); - uint8_t adv_size = gap_event_advertising_report_get_data_length(packet); - ad_context_t context; - for (ad_iterator_init(&context, adv_size, adv_data); ad_iterator_has_more(&context); ad_iterator_next(&context)) { - uint8_t data_type = ad_iterator_get_data_type(&context); - if (data_type != BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME) { - continue; + switch (packet_type) + { + case HCI_EVENT_PACKET: + event = hci_event_packet_get_type(packet); + switch (event) + { + case BTSTACK_EVENT_STATE: + if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) + break; + btstack_assert(app_state == W4_WORKING); + + hog_start_connect(); + break; + case GAP_EVENT_ADVERTISING_REPORT: + { + // store remote device address and type + bd_addr_t address; + bool has_name = false; + gap_event_advertising_report_get_address(packet, address); + const uint8_t *adv_data = gap_event_advertising_report_get_data(packet); + uint8_t adv_size = gap_event_advertising_report_get_data_length(packet); + ad_context_t context; + + char *address_string = bd_addr_to_str(address); + bool found = false; + int current_device = devices_found; + for (int i = 0; i < devices_found; i++) + { + if (memcmp(address_string, devices[i].addr, SIZE_OF_BD_ADDRESS) == 0) + { + found = true; + current_device = i; + } + } + for (ad_iterator_init(&context, adv_size, adv_data); ad_iterator_has_more(&context); ad_iterator_next(&context)) + { + uint8_t data_type = ad_iterator_get_data_type(&context); + uint8_t data_len = ad_iterator_get_data_len(&context); + const uint8_t *data = ad_iterator_get_data(&context); + + uint8_t i; + uint8_t ad_uuid128[16], uuid128_bt[16]; + switch (data_type) + { + case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS: + case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS: + for (i = 0u; (i + 2u) <= data_len; i += 2u) + { + uint16_t uuid = (uint16_t)little_endian_read_16(data, (int)i); + if (uuid == ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE) + { + if (!found) + { + memcpy(devices[devices_found].addr, address_string, SIZE_OF_BD_ADDRESS); + devices[devices_found].name_buffer[0] = ' '; + devices[devices_found].name_buffer[0 + 1] = '('; + memcpy(devices[devices_found].name_buffer + 0 + 2, address_string, SIZE_OF_BD_ADDRESS); + devices[devices_found].name_buffer[0 + SIZE_OF_BD_ADDRESS + 1] = ')'; + devices[devices_found].name_buffer[0 + SIZE_OF_BD_ADDRESS + 2] = 0; + found = true; + devices_found++; + printf("found device: %s\n", devices[devices_found - 1].name_buffer); + } + break; } - uint8_t size = ad_iterator_get_data_len(&context); - const uint8_t *data = ad_iterator_get_data(&context); - char *address_string = bd_addr_to_str(address); - bool found = false; - int current_device = devices_found; - for (int i = 0; i < devices_found; i++) { - if (memcmp(address_string, devices[i].addr, SIZE_OF_BD_ADDRESS) == 0) { + } + continue; + case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS: + case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS: + uuid_add_bluetooth_prefix(ad_uuid128, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE); + reverse_128(ad_uuid128, uuid128_bt); + for (i = 0u; (i + 16u) <= data_len; i += 16u) + { + if (memcmp(uuid128_bt, &data[i], 16) == 0) + { + if (!found) + { + memcpy(devices[devices_found].addr, address_string, SIZE_OF_BD_ADDRESS); + devices[devices_found].name_buffer[0] = ' '; + devices[devices_found].name_buffer[0 + 1] = '('; + memcpy(devices[devices_found].name_buffer + 0 + 2, address_string, SIZE_OF_BD_ADDRESS); + devices[devices_found].name_buffer[0 + SIZE_OF_BD_ADDRESS + 1] = ')'; + devices[devices_found].name_buffer[0 + SIZE_OF_BD_ADDRESS + 2] = 0; found = true; + devices_found++; + printf("found device: %s\n", devices[devices_found - 1].name_buffer); } + break; } - if (!found) { + } + continue; + case BLUETOOTH_DATA_TYPE_APPEARANCE: + if (little_endian_read_16(data, 0) == 0x03C4) + { + if (!found) + { memcpy(devices[devices_found].addr, address_string, SIZE_OF_BD_ADDRESS); - memcpy(devices[devices_found].name_buffer, data, size); - devices[devices_found].name_buffer[size] = ' '; - devices[devices_found].name_buffer[size + 1] = '('; - memcpy(devices[devices_found].name_buffer + size + 2, address_string, SIZE_OF_BD_ADDRESS); - devices[devices_found].name_buffer[size + SIZE_OF_BD_ADDRESS + 1] = ')'; - devices[devices_found].name_buffer[size + SIZE_OF_BD_ADDRESS + 2] = 0; - printf("Found device '%s'\r\n", devices[devices_found].name_buffer); + devices[devices_found].name_buffer[0] = ' '; + devices[devices_found].name_buffer[0 + 1] = '('; + memcpy(devices[devices_found].name_buffer + 0 + 2, address_string, SIZE_OF_BD_ADDRESS); + devices[devices_found].name_buffer[0 + SIZE_OF_BD_ADDRESS + 1] = ')'; + devices[devices_found].name_buffer[0 + SIZE_OF_BD_ADDRESS + 2] = 0; + found = true; devices_found++; + printf("found device name: %s\n", devices[devices_found - 1].name_buffer); } } - break; - } - case HCI_EVENT_DISCONNECTION_COMPLETE: - if (app_state != READY) break; - hids_client_disconnect(hids_cid); - connection_handle = HCI_CON_HANDLE_INVALID; - switch (app_state) { - case READY: - printf("\r\nDisconnected, try to reconnect...\r\n"); - app_state = W4_TIMEOUT_THEN_RECONNECT; - break; - default: - printf("\r\nDisconnected, start over...\r\n"); - app_state = W4_TIMEOUT_THEN_SCAN; - break; + continue; + case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME: + if (found) + { + memcpy(devices[current_device].name_buffer, data, data_len); + devices[current_device].name_buffer[data_len] = ' '; + devices[current_device].name_buffer[data_len + 1] = '('; + memcpy(devices[current_device].name_buffer + data_len + 2, address_string, SIZE_OF_BD_ADDRESS); + devices[current_device].name_buffer[data_len + SIZE_OF_BD_ADDRESS + 1] = ')'; + devices[current_device].name_buffer[data_len + SIZE_OF_BD_ADDRESS + 2] = 0; + has_name = true; + printf("has name '%s'\r\n", devices[current_device].name_buffer); } - hog_start_reconnect_timer(); - break; - - case HCI_EVENT_LE_META: - switch (hci_event_le_meta_get_subevent_code(packet)) { - case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: { - // print connection parameters (without using float operations) - uint16_t conn_interval = hci_subevent_le_connection_complete_get_conn_interval(packet); - printf("LE Connection Complete:\r\n"); - printf("- Connection Interval: %u.%02u ms\r\n", conn_interval * 125 / 100, 25 * (conn_interval & 3)); - printf("- Connection Latency: %u\r\n", hci_subevent_le_connection_complete_get_conn_latency(packet)); - break; - } - case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE: { - // print connection parameters (without using float operations) - uint16_t conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet); - printf("LE Connection Update:\r\n"); - printf("- Connection Interval: %u.%02u ms\r\n", conn_interval * 125 / 100, 25 * (conn_interval & 3)); - printf("- Connection Latency: %u\r\n", hci_subevent_le_connection_update_complete_get_conn_latency(packet)); - break; - } - default: - break; - } - // wait for connection complete - if (hci_event_le_meta_get_subevent_code(packet) != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break; - if (app_state != W4_CONNECTED) return; - btstack_run_loop_remove_timer(&connection_timer); - connection_handle = hci_subevent_le_connection_complete_get_connection_handle(packet); - // request security - app_state = W4_ENCRYPTED; - sm_request_pairing(connection_handle); - break; - default: - break; + continue; + } + } + break; + } + case HCI_EVENT_DISCONNECTION_COMPLETE: + if (app_state != READY) + break; + hids_host_disconnect(hids_cid); + connection_handle = HCI_CON_HANDLE_INVALID; + switch (app_state) + { + case READY: + printf("\r\nDisconnected, try to reconnect...\r\n"); + app_state = W4_TIMEOUT_THEN_RECONNECT; + break; + default: + printf("\r\nDisconnected, start over...\r\n"); + app_state = W4_TIMEOUT_THEN_SCAN; + break; + } + hog_start_reconnect_timer(); + break; + case HCI_EVENT_META_GAP: + // wait for connection complete + if (hci_event_gap_meta_get_subevent_code(packet) != GAP_SUBEVENT_LE_CONNECTION_COMPLETE) break; + if (app_state != W4_CONNECTED) return; + btstack_run_loop_remove_timer(&connection_timer); + connection_handle = gap_subevent_le_connection_complete_get_connection_handle(packet); + // request security + app_state = W4_ENCRYPTED; + sm_request_pairing(connection_handle); + break; + case HCI_EVENT_LE_META: + printf("hci evt le: %02x\r\n", hci_event_le_meta_get_subevent_code(packet)); + switch (hci_event_le_meta_get_subevent_code(packet)) + { + case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: + { + // print connection parameters (without using float operations) + uint16_t conn_interval = hci_subevent_le_connection_complete_get_conn_interval(packet); + printf("LE Connection Complete:\r\n"); + printf("- Connection Interval: %u.%02u ms\r\n", conn_interval * 125 / 100, 25 * (conn_interval & 3)); + printf("- Connection Latency: %u\r\n", hci_subevent_le_connection_complete_get_conn_latency(packet)); + break; + } + case HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE: + connection_handle = hci_subevent_le_data_length_change_get_connection_handle(packet); + printf("- LE Connection 0x%04x: data length change - max %u bytes per packet\n", connection_handle, + hci_subevent_le_data_length_change_get_max_tx_octets(packet)); + break; + case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE: + { + // print connection parameters (without using float operations) + uint16_t conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet); + printf("LE Connection Update:\r\n"); + printf("- Connection Interval: %u.%02u ms\r\n", conn_interval * 125 / 100, 25 * (conn_interval & 3)); + printf("- Connection Latency: %u\r\n", hci_subevent_le_connection_update_complete_get_conn_latency(packet)); + break; + } + default: + break; } break; default: break; + } + break; + default: + break; } } /* LISTING_END */ @@ -439,64 +575,69 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe /* LISTING_START(SMPacketHandler): Scanning and receiving advertisements */ -static void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { +static void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) +{ UNUSED(channel); UNUSED(size); - if (packet_type != HCI_EVENT_PACKET) return; - - switch (hci_event_packet_get_type(packet)) { - case SM_EVENT_JUST_WORKS_REQUEST: - printf("Just works requested\r\n"); - sm_just_works_confirm(sm_event_just_works_request_get_handle(packet)); - break; - case SM_EVENT_NUMERIC_COMPARISON_REQUEST: - printf("Confirming numeric comparison: %" PRIu32 "\r\n", sm_event_numeric_comparison_request_get_passkey(packet)); - sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet)); + if (packet_type != HCI_EVENT_PACKET) + return; + printf("hci evt: %02x\r\n", hci_event_packet_get_type(packet)); + switch (hci_event_packet_get_type(packet)) + { + case SM_EVENT_JUST_WORKS_REQUEST: + printf("Just works requested\r\n"); + sm_just_works_confirm(sm_event_just_works_request_get_handle(packet)); + break; + case SM_EVENT_NUMERIC_COMPARISON_REQUEST: + printf("Confirming numeric comparison: %" PRIu32 "\r\n", sm_event_numeric_comparison_request_get_passkey(packet)); + sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet)); + break; + case SM_EVENT_PASSKEY_DISPLAY_NUMBER: + printf("Display Passkey: %" PRIu32 "\r\n", sm_event_passkey_display_number_get_passkey(packet)); + break; + case SM_EVENT_PAIRING_COMPLETE: + switch (sm_event_pairing_complete_get_status(packet)) + { + case ERROR_CODE_SUCCESS: + printf("Pairing complete, success\r\n"); + + // continue - query primary services + printf("Search for HID service.\r\n"); + app_state = W4_HID_CLIENT_CONNECTED; + // TODO: figure out why device_information_service isnt working anymore + device_information_service_client_query(connection_handle, handle_gatt_client_event); + // hids_host_connect(connection_handle, handle_gatt_client_event, protocol_mode, &hids_cid); break; - case SM_EVENT_PASSKEY_DISPLAY_NUMBER: - printf("Display Passkey: %" PRIu32 "\r\n", sm_event_passkey_display_number_get_passkey(packet)); + case ERROR_CODE_CONNECTION_TIMEOUT: + printf("Pairing failed, timeout\r\n"); + hog_start_reconnect_timer(); break; - case SM_EVENT_PAIRING_COMPLETE: - switch (sm_event_pairing_complete_get_status(packet)) { - case ERROR_CODE_SUCCESS: - printf("Pairing complete, success\r\n"); - - // continue - query primary services - printf("Search for HID service.\r\n"); - app_state = W4_HID_CLIENT_CONNECTED; - // TODO: figure out why device_information_service isnt working anymore - device_information_service_client_query(connection_handle, handle_gatt_client_event); - // hids_client_connect(connection_handle, handle_gatt_client_event, protocol_mode, &hids_cid); - break; - case ERROR_CODE_CONNECTION_TIMEOUT: - printf("Pairing failed, timeout\r\n"); - hog_start_reconnect_timer(); - break; - case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION: - printf("Pairing failed, disconnected\r\n"); - hog_start_reconnect_timer(); - break; - case ERROR_CODE_AUTHENTICATION_FAILURE: - printf("Pairing failed, reason = %u\r\n", sm_event_pairing_complete_get_reason(packet)); - hog_start_reconnect_timer(); - break; - default: - break; - } + case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION: + printf("Pairing failed, disconnected\r\n"); + hog_start_reconnect_timer(); break; - case SM_EVENT_REENCRYPTION_COMPLETE: - printf("Re-encryption complete, success\n"); - app_state = W4_HID_CLIENT_CONNECTED; - device_information_service_client_query(connection_handle, handle_gatt_client_event); + case ERROR_CODE_AUTHENTICATION_FAILURE: + printf("Pairing failed, reason = %u\r\n", sm_event_pairing_complete_get_reason(packet)); + hog_start_reconnect_timer(); break; default: break; + } + break; + case SM_EVENT_REENCRYPTION_COMPLETE: + printf("Re-encryption complete, success\n"); + app_state = W4_HID_CLIENT_CONNECTED; + device_information_service_client_query(connection_handle, handle_gatt_client_event); + break; + default: + break; } } /* LISTING_END */ -int btstack_main(void) { +int btstack_main(void) +{ printf("Bt init\r\n"); #ifdef BT_ADDR #ifdef CONFIGURABLE_BLOBS @@ -504,13 +645,25 @@ int btstack_main(void) { #else has_address = true; #endif - if (has_address) { + if (has_address) + { sscanf_bd_addr(bt_addr, remote_device.addr); remote_device.addr_type = BD_ADDR_TYPE_LE_PUBLIC; } #endif + /* LISTING_START(HogBootHostSetup): HID-over-GATT Host Setup */ + // hci_dump_init(hci_dump_embedded_stdout_get_instance()); + + // + l2cap_init(); + sm_init(); + sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY); + sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION | SM_AUTHREQ_BONDING); + gatt_client_init(); + hids_host_init(hid_descriptor_storage, sizeof(hid_descriptor_storage)); + device_information_service_client_init(); // register for events from HCI hci_event_callback_registration.callback = &packet_handler; hci_add_event_handler(&hci_event_callback_registration); @@ -518,14 +671,8 @@ int btstack_main(void) { // register for events from Security Manager sm_event_callback_registration.callback = &sm_packet_handler; sm_add_event_handler(&sm_event_callback_registration); + sm_set_authentication_requirements( SM_AUTHREQ_BONDING); - // - l2cap_init(); - sm_init(); - gatt_client_init(); - - hids_client_init(hid_descriptor_storage, sizeof(hid_descriptor_storage)); - device_information_service_client_init(); app_state = W4_WORKING; // Turn on the device diff --git a/src/pico/bt_rx_cnt.cpp b/src/pico/bt_rx_cnt.cpp index 71ab65eb7..ce51f4339 100644 --- a/src/pico/bt_rx_cnt.cpp +++ b/src/pico/bt_rx_cnt.cpp @@ -59,7 +59,7 @@ enum STATE state = INIT; static uint16_t hid_host_cid = 0; static bool hid_host_descriptor_available = false; -static hid_protocol_mode_t hid_host_report_mode = HID_PROTOCOL_MODE_REPORT_WITH_FALLBACK_TO_BOOT; +static hid_protocol_mode_t hid_host_report_mode = HID_PROTOCOL_MODE_REPORT; static HID_ReportInfo_t *info; int get_bt_address(uint8_t *addr) { diff --git a/src/pico/io.cpp b/src/pico/io.cpp index 9e9154b92..f921c0643 100644 --- a/src/pico/io.cpp +++ b/src/pico/io.cpp @@ -16,7 +16,8 @@ #include "pico_slave.h" #include "wii.h" volatile bool spi_acknowledged = false; -void spi_begin_output() { +void spi_begin_output() +{ #ifdef SPI_0_OUTPUT #ifdef SPI_0_MOSI spi_init(spi0, SPI_0_CLOCK); @@ -50,7 +51,8 @@ void spi_begin_output() { spi_set_slave(spi1, true); #endif } -void spi_begin() { +void spi_begin() +{ #ifdef SPI_0_MOSI spi_init(spi0, SPI_0_CLOCK); spi_set_format(spi0, 8, (spi_cpol_t)SPI_0_CPOL, @@ -84,7 +86,47 @@ void spi_begin() { spi_set_slave(spi1, true); #endif } -static uint8_t revbits(uint8_t b) { +void uart_begin() +{ +#ifdef UART_0_TX + uart_init(uart0, UART_0_CLOCK); + gpio_set_function(UART_0_TX, GPIO_FUNC_UART); + gpio_set_function(UART_0_RX, GPIO_FUNC_UART); +#endif +#ifdef UART_1_TX + uart_init(uart1, UART_1_CLOCK); + gpio_set_function(UART_1_TX, GPIO_FUNC_UART); + gpio_set_function(UART_1_RX, GPIO_FUNC_UART); +#endif +} +bool read_uart(UART_BLOCK block, uint8_t header, uint8_t size, uint8_t *dest) +{ + if (!uart_is_readable(block)) + { + return false; + } + while (uart_getc(block) != header) + { + if (!uart_is_readable(block)) + { + return false; + } + } + uart_read_blocking(block, dest, size); + return true; +} + +void send_uart(UART_BLOCK block, uint8_t *data, uint8_t size) +{ + + if (!uart_is_writable(block)) + { + return; + } + uart_write_blocking(block, data, size); +} +static uint8_t revbits(uint8_t b) +{ b = (b & 0b11110000) >> 4 | (b & 0b00001111) << 4; b = (b & 0b11001100) >> 2 | (b & 0b00110011) << 2; b = (b & 0b10101010) >> 1 | (b & 0b01010101) << 1; @@ -94,27 +136,33 @@ static uint8_t revbits(uint8_t b) { volatile bool alarm_fired = false; #define ALARM_NUM 0 #define ALARM_IRQ TIMER_IRQ_0 -int64_t alarm_irq(alarm_id_t id, void *user_data) { +int64_t alarm_irq(alarm_id_t id, void *user_data) +{ alarm_fired = true; return 0; } -int __not_in_flash_func(spi_write_read_blocking_timeout)(spi_inst_t *spi, const uint8_t src) { +int __not_in_flash_func(spi_write_read_blocking_timeout)(spi_inst_t *spi, const uint8_t src) +{ // For PS2 communication we NEED timeouts. We can fake them by starting an alarm and resetting the SPI // hardware if the alarm fires. size_t rx_remaining = 1, tx_remaining = 1; uint8_t dst; alarm_fired = false; alarm_id_t alarm = add_alarm_in_us(50, alarm_irq, NULL, false); - while (rx_remaining || tx_remaining) { - if (tx_remaining && spi_is_writable(spi)) { + while (rx_remaining || tx_remaining) + { + if (tx_remaining && spi_is_writable(spi)) + { spi_get_hw(spi)->dr = (uint32_t)src; --tx_remaining; } - if (rx_remaining && spi_is_readable(spi)) { + if (rx_remaining && spi_is_readable(spi)) + { dst = (uint8_t)spi_get_hw(spi)->dr; --rx_remaining; } - if (alarm_fired) { + if (alarm_fired) + { spi_begin_output(); return 0; } @@ -123,50 +171,62 @@ int __not_in_flash_func(spi_write_read_blocking_timeout)(spi_inst_t *spi, const return dst; } // SINCE LSB_FIRST isn't supported, we need to invert bits ourselves when its set -uint8_t spi_transfer(SPI_BLOCK block, uint8_t data) { +uint8_t spi_transfer(SPI_BLOCK block, uint8_t data) +{ #if SPI_0_MSBFIRST == 0 - if (block == spi0) data = revbits(data); + if (block == spi0) + data = revbits(data); #endif #if SPI_1_MSBFIRST == 0 - if (block == spi1) data = revbits(data); + if (block == spi1) + data = revbits(data); #endif uint8_t resp; #ifdef SPI_1_OUTPUT - if (block == spi1) { + if (block == spi1) + { resp = spi_write_read_blocking_timeout(block, data); } #endif #ifndef SPI_1_OUTPUT - if (block == spi1) { + if (block == spi1) + { spi_write_read_blocking(block, &data, &resp, 1); } #endif #ifdef SPI_0_OUTPUT - if (block == spi0) { + if (block == spi0) + { resp = spi_write_read_blocking_timeout(block, data); } #endif #ifndef SPI_0_OUTPUT - if (block == spi0) { + if (block == spi0) + { spi_write_read_blocking(block, &data, &resp, 1); } #endif #if SPI_0_MSBFIRST == 0 - if (block == spi0) resp = revbits(resp); + if (block == spi0) + resp = revbits(resp); #endif #if SPI_1_MSBFIRST == 0 - if (block == spi1) resp = revbits(resp); + if (block == spi1) + resp = revbits(resp); #endif return resp; } void spi_high(SPI_BLOCK block) {} uint8_t addr; -void recv(int len) { +void recv(int len) +{ addr = RXWIRE.read(); // remove addr len -= 1; - if (len) { - for (int i = 0; i < len; i++) { + if (len) + { + for (int i = 0; i < len; i++) + { recv_data(addr + i, RXWIRE.read()); } recv_end(addr, len); @@ -174,11 +234,13 @@ void recv(int len) { } // Called when the I2C slave is read from -void req() { +void req() +{ // Auto increment address for repeated reads RXWIRE.write(req_data(addr++)); } -void twi_init() { +void twi_init() +{ #ifdef TWI_0_CLOCK i2c_init(i2c0, TWI_0_CLOCK); gpio_set_function(TWI_0_SDA, GPIO_FUNC_I2C); @@ -216,20 +278,24 @@ void twi_init() { #endif } bool twi_readFromPointerSlow(TWI_BLOCK block, uint8_t address, uint8_t pointer, uint8_t length, - uint8_t *data) { - if (!twi_writeTo(block, address, &pointer, 1, true, true)) return false; + uint8_t *data) +{ + if (!twi_writeTo(block, address, &pointer, 1, true, true)) + return false; delayMicroseconds(170); return twi_readFrom(block, address, data, length, true); } bool twi_readFrom(TWI_BLOCK block, uint8_t address, uint8_t *data, uint8_t length, - uint8_t sendStop) { + uint8_t sendStop) +{ int ret = i2c_read_timeout_us(block, address, data, length, !sendStop, 5000); return ret > 0 ? ret : 0; } bool twi_writeTo(TWI_BLOCK block, uint8_t address, uint8_t *data, uint8_t length, uint8_t wait, - uint8_t sendStop) { + uint8_t sendStop) +{ int ret = i2c_write_timeout_us(block, address, data, length, !sendStop, 5000); if (ret < 0) @@ -239,15 +305,18 @@ bool twi_writeTo(TWI_BLOCK block, uint8_t address, uint8_t *data, uint8_t length } #ifdef PS2_ACK -void callback(uint gpio, uint32_t events) { +void callback(uint gpio, uint32_t events) +{ spi_acknowledged = true; } -void init_ack() { +void init_ack() +{ gpio_set_irq_enabled_with_callback(PS2_ACK, GPIO_IRQ_EDGE_RISE, true, &callback); } #endif -void read_serial(uint8_t *id, uint8_t len) { +void read_serial(uint8_t *id, uint8_t len) +{ pico_get_unique_board_id_string((char *)id, len); } @@ -259,51 +328,63 @@ uint32_t lastWtSum[5] = {0}; uint32_t lastWtAvg[5][WT_BUFFER] = {0}; uint8_t nextWt[5] = {0}; uint32_t initialWt[5] = {0}; -uint32_t readWt(int pin) { +uint32_t readWt(int pin) +{ gpio_put_masked((1 << WT_PIN_S0) | (1 << WT_PIN_S1) | (1 << WT_PIN_S2), ((pin & (1 << 0)) << WT_PIN_S0 - 0) | ((pin & (1 << 1)) << (WT_PIN_S1 - 1)) | ((pin & (1 << 2)) << (WT_PIN_S2 - 2))); uint32_t m = rp2040.getCycleCount(); gpio_put(WT_PIN_INPUT, 1); gpio_set_dir(WT_PIN_INPUT, true); gpio_set_dir(WT_PIN_INPUT, false); gpio_set_pulls(WT_PIN_INPUT, false, false); - while (gpio_get(WT_PIN_INPUT)) { - if (rp2040.getCycleCount() - m > 10000) { + while (gpio_get(WT_PIN_INPUT)) + { + if (rp2040.getCycleCount() - m > 10000) + { break; } } m = rp2040.getCycleCount() - m; - if (pin >= 6) { + if (pin >= 6) + { return m; } lastWtSum[pin] -= lastWtAvg[pin][nextWt[pin]]; lastWtAvg[pin][nextWt[pin]] = m; lastWtSum[pin] += m; nextWt[pin]++; - if (nextWt[pin] >= WT_BUFFER) { + if (nextWt[pin] >= WT_BUFFER) + { nextWt[pin] = 0; } m = lastWtSum[pin] / WT_BUFFER; lastWt[pin] = m; return m; } -bool checkWt(int pin) { +bool checkWt(int pin) +{ return readWt(pin) > initialWt[pin]; } -void initWt() { +void initWt() +{ memset(initialWt, 0, sizeof(initialWt)); - for (int j = 0; j < 1000; j++) { - for (int i = 0; i < 5; i++) { + for (int j = 0; j < 1000; j++) + { + for (int i = 0; i < 5; i++) + { initialWt[i] += readWt(i); } } - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { initialWt[i] /= 1000; initialWt[i] += WT_SENSITIVITY; } } static bool wtInit = false; -uint8_t tickWt() { - if (!wtInit) { +uint8_t tickWt() +{ + if (!wtInit) + { wtInit = true; initWt(); } diff --git a/src/pico/io_define.h b/src/pico/io_define.h index 343e5506e..8c41df335 100644 --- a/src/pico/io_define.h +++ b/src/pico/io_define.h @@ -3,6 +3,7 @@ #include #include #include +#include #if BLUETOOTH #include #endif @@ -13,5 +14,8 @@ #define TWI_1 i2c1 #define SPI_0 spi0 #define SPI_1 spi1 +#define UART_0 uart0 +#define UART_1 uart1 #define TWI_BLOCK i2c_inst_t* -#define SPI_BLOCK spi_inst_t* \ No newline at end of file +#define SPI_BLOCK spi_inst_t* +#define UART_BLOCK uart_inst_t* \ No newline at end of file diff --git a/src/pico/main.cpp b/src/pico/main.cpp index 8ba408d8e..4396fc570 100644 --- a/src/pico/main.cpp +++ b/src/pico/main.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "commands.h" #include "common/tusb_types.h" @@ -16,7 +17,6 @@ #include "hardware/structs/usb.h" #include "hardware/watchdog.h" #include "hid.h" -#include "hidescriptorparser.h" #include "host/usbh.h" #include "host/usbh_pvt.h" #include "io.h" @@ -29,15 +29,12 @@ #include "shared_main.h" #include "xinput_device.h" #include "xinput_host.h" -#if defined(INPUT_USB_HOST) || defined(INPUT_SERIAL_MIDI) -#include "TUSB-MIDI.hpp" -#endif #if BLUETOOTH #include "bt.h" #include "pico/cyw43_arch.h" #endif -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t buf[255]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t buf[512]; CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t buf2[255]; CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN STRING_DESCRIPTOR_PICO serialstring = { .bLength = (sizeof(uint8_t) + sizeof(uint8_t) + (SERIAL_LEN + 3) * 2), @@ -49,28 +46,31 @@ static uint32_t __uninitialized_ram(windows_in_hid); static uint32_t __uninitialized_ram(persistedConsoleTypeValid); static uint32_t __uninitialized_ram(xboxAuthValid); static uint32_t __uninitialized_ram(pico_is_sleeping); -bool connected = false; +static uint32_t __uninitialized_ram(persistedProGuitarType); #if USB_HOST_STACK USB_Device_Type_t xone_dev_addr = {}; USB_Device_Type_t x360_dev_addr = {}; USB_Device_Type_t ps4_dev_addr = {}; +USB_Device_Type_t ps5_dev_addr = {}; uint8_t total_usb_host_devices = 0; -typedef struct { +typedef struct +{ USB_Device_Type_t type; USB_LastReport_Data_t report; uint8_t report_length; bool switch_sent_timeout; - bool switch_sent_handshake; uint8_t xone_init_id; } Usb_Host_Device_t; Usb_Host_Device_t usb_host_devices[CFG_TUH_DEVICE_MAX * CFG_TUH_XINPUT]; #endif -typedef enum { - PIO_USB_PINOUT_DPDM = 0, // DM = DP+1 - PIO_USB_PINOUT_DMDP, // DM = DP-1 +typedef enum +{ + PIO_USB_PINOUT_DPDM = 0, // DM = DP+1 + PIO_USB_PINOUT_DMDP, // DM = DP-1 } PIO_USB_PINOUT; -typedef struct { +typedef struct +{ uint8_t pin_dp; uint8_t pio_tx_num; uint8_t sm_tx; @@ -86,106 +86,172 @@ typedef struct { } pio_usb_configuration_t; uint8_t prev_bt_report[32]; static const uint8_t capabilitiesRequest[] = {0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t xbox360w_prescence[] = {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -#ifdef INPUT_USB_HOST -using namespace usbMidi; -UsbMidiTransport usbMIDITransport(0); -MidiInterface MIDI(usbMIDITransport); -#endif -#ifdef INPUT_SERIAL_MIDI -#if SERIAL_MIDI_PIN == 5 || SERIAL_MIDI_PIN == 9 || SERIAL_MIDI_PIN == 20 -SerialMIDI serialMIDI(Serial2); -#else -SerialMIDI serialMIDI(Serial1); -#endif -MidiInterface> MIDI2(serialMIDI); -#endif -bool ready_for_next_packet() { +static const uint8_t xbox360w_prescence[] = {0x08, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +bool ready_for_next_packet() +{ return tud_xinput_n_ready(0) && tud_ready_for_packet(); } -bool usb_configured() { - return connected; +bool usb_configured() +{ + return tud_ready(); } -void send_report_to_pc(const void *report, uint8_t len) { +bool ps5_auth_ready = 0; +uint8_t hash_pending_buffer[64]; +uint8_t hash_finish_buffer[64]; + +uint8_t auth_buffer[64]; +bool dongle_ready = false; +bool hash_pending = false; +bool hash_ready = false; +uint32_t hash_timer; +void send_report_to_pc(const void *report, uint8_t len) +{ +#if USB_HOST_STACK + if (consoleType == PS5 && ps5_dev_addr.dev_addr) + { + if (hash_pending) + { + return; + } + hash_pending = true; + send_report_to_controller(ps5_dev_addr.dev_addr, ps5_dev_addr.instance, (const uint8_t *)report, len); + return; + } +#endif tud_xusb_n_report(0, report, len); } bool foundXB = false; bool authReady = false; bool authDone = false; long test3 = 0; -static void tick_usb() { -#if USB_HOST_STACK - if (consoleType == XBOX360 && !foundXB && xboxAuthValid) { - tuh_task(); - return; +static void on_uart_rx_0() +{ + while (uart_is_readable(uart0)) + { + uint8_t data = uart_getc(uart0); + serialMidi.processMidiData(&data, 1); } - if (consoleType == XBOXONE && !foundXB) { - tuh_task(); - return; +} + +static void on_uart_rx_1() +{ + while (uart_is_readable(uart1)) + { + uint8_t data = uart_getc(uart1); + serialMidi.processMidiData(&data, 1); } -#endif +} +static void tick_usb() +{ tud_task(); #if USB_HOST_STACK tuh_task(); #endif - if (tud_suspended()) { - tud_remote_wakeup(); - } tick(); -#ifdef INPUT_USB_HOST - MIDI.read(); -#endif -#ifdef INPUT_SERIAL_MIDI - MIDI2.read(); -#endif - if (!authDone) { - if (consoleType != XBOXONE && (consoleType != XBOX360 || !xboxAuthValid)) { - authReady = millis() > 1000; - } - if (authReady) { - authDone = true; - } - } } #if BLUETOOTH_RX -void tick_bluetooth(const void *buf, uint8_t len, USB_Device_Type_t type) { +void tick_bluetooth(const void *buf, uint8_t len, USB_Device_Type_t type) +{ tick_bluetooth_inputs(buf, len, type); } #endif #if BLUETOOTH -void loop1() { +void loop1() +{ } -void setup1() { +void setup1() +{ btstack_main(); } #endif -void loop() { +void loop() +{ tick_usb(); } +void setArcadeSide(uint8_t side) +{ + if (arcadeSide == side) + { + return; + } + arcadeSide = side; + EEPROM.write(0, side); + EEPROM.commit(); +} -void go_to_sleep() { +void go_to_sleep() +{ pico_is_sleeping = true; reset_usb(); } -void setup() { +void wakeup_360() +{ + if (tud_suspended()) + { + tud_remote_wakeup(); + } + if (usb_configured()) + { + return; + } + // the 360 will wake up the console if it sees the data lines being driven high and low constantly + // save the previous usb state + uint32_t prev_direct = usb_hw->phy_direct; + uint32_t prev_direct_override = usb_hw->phy_direct_override; + for (int i = 0; i < 2; i++) + { + // drive both pins high + hw_set_bits(&usb_hw->phy_direct_override, USB_USBPHY_DIRECT_OVERRIDE_TX_DM_OE_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_TX_DM_OVERRIDE_EN_BITS | + USB_USBPHY_DIRECT_OVERRIDE_TX_DP_OE_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_TX_DP_OVERRIDE_EN_BITS | USB_USBPHY_DIRECT_OVERRIDE_TX_DIFFMODE_OVERRIDE_EN_BITS); + hw_set_bits(&usb_hw->phy_direct, USB_USBPHY_DIRECT_TX_DM_OE_BITS | USB_USBPHY_DIRECT_TX_DP_OE_BITS | USB_USBPHY_DIRECT_TX_DIFFMODE_BITS); + hw_clear_bits(&usb_hw->phy_direct, USB_USBPHY_DIRECT_TX_DIFFMODE_BITS); + hw_set_bits(&usb_hw->phy_direct, USB_USBPHY_DIRECT_TX_DP_BITS | USB_USBPHY_DIRECT_TX_DM_BITS); + // wait a bit + sleep_ms(1); + // revert the pin state + usb_hw->phy_direct = prev_direct; + usb_hw->phy_direct_override = prev_direct_override; + sleep_ms(1000); + } + // Reset the pico just to make sure any other state is reset in case this was triggered by usb host + reset_usb(); +} + +void setup() +{ #if USB_HOST_STACK - set_sys_clock_khz(120000, true); + set_sys_clock_khz(180000, true); #endif + #ifdef INPUT_SERIAL_MIDI -#if SERIAL_MIDI_PIN == 5 || SERIAL_MIDI_PIN == 9 || SERIAL_MIDI_PIN == 20 - Serial2.setRX(SERIAL_MIDI_PIN); +#if SERIAL_MIDI_PIN == 1 || SERIAL_MIDI_PIN == 13 || SERIAL_MIDI_PIN == 17 + uart_init(uart0, 31250); + gpio_set_function(SERIAL_MIDI_PIN, GPIO_FUNC_UART); + irq_set_exclusive_handler(UART0_IRQ, on_uart_rx_0); + irq_set_enabled(UART0_IRQ, true); + + uart_set_irqs_enabled(uart0, true, false); #else - Serial1.setRX(SERIAL_MIDI_PIN); + uart_init(uart1, 31250); + gpio_set_function(SERIAL_MIDI_PIN, GPIO_FUNC_UART); + irq_set_exclusive_handler(UART1_IRQ, on_uart_rx_1); + irq_set_enabled(UART1_IRQ, true); + + uart_set_irqs_enabled(uart1, true, false); #endif #endif - if (persistedConsoleTypeValid == PERSISTED_CONSOLE_TYPE_VALID) { + if (persistedConsoleTypeValid == PERSISTED_CONSOLE_TYPE_VALID) + { consoleType = persistedConsoleType; - if (SLEEP_PIN != -1) { + proGuitarType = persistedProGuitarType; + if (SLEEP_PIN != -1) + { // Sleep works best when nothing else is started, so we reboot the pico before and after sleep - if (pico_is_sleeping) { + if (pico_is_sleeping) + { pinMode(SLEEP_PIN, SLEEP_ACTIVE_HIGH ? INPUT_PULLDOWN : INPUT_PULLUP); sleep_run_from_xosc(); sleep_goto_dormant_until_pin(SLEEP_PIN, true, SLEEP_ACTIVE_HIGH); @@ -194,15 +260,29 @@ void setup() { reset_usb(); } } - } else { + } + else + { windows_in_hid = false; xboxAuthValid = false; consoleType = UNIVERSAL; + proGuitarType = DEVICE_TYPE; + pico_is_sleeping = false; } generateSerialString(&serialstring, consoleType); printf("ConsoleType: %d\r\n", consoleType); + + EEPROM.begin(512); + arcadeSide = EEPROM.read(0); + if (arcadeSide > 2) + { + arcadeSide = 1; + } init_main(); - tud_init(TUD_OPT_RHPORT); + const tusb_rhport_init_t rd_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUD_OPT_HIGH_SPEED ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL}; + tud_rhport_init(TUD_OPT_RHPORT, &rd_init); #if USB_HOST_STACK pio_usb_configuration_t config = { pin_dp : USB_HOST_DP_PIN, @@ -218,88 +298,94 @@ void setup() { skip_alarm_pool : false, pinout : PIO_USB_PINOUT_DPDM }; - tuh_configure(0, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &config); - tuh_init(TUH_OPT_RHPORT); -#ifdef INPUT_USB_HOST - MIDI.begin(0); - MIDI.setHandleNoteOn(onNote); - MIDI.setHandleNoteOff(offNote); - MIDI.setHandleControlChange(onControlChange); - MIDI.setHandlePitchBend(onPitchBend); -#endif -#ifdef INPUT_SERIAL_MIDI - MIDI2.begin(0); - MIDI2.setHandleNoteOn(onNote); - MIDI2.setHandleNoteOff(offNote); - MIDI2.setHandleControlChange(onControlChange); - MIDI2.setHandlePitchBend(onPitchBend); -#endif + tuh_configure(TUH_OPT_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &config); + const tusb_rhport_init_t rh_init = { + .role = TUSB_ROLE_HOST, + .speed = TUH_OPT_HIGH_SPEED ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, + }; + tuh_rhport_init(TUH_OPT_RHPORT, &rh_init); #endif } #ifdef INPUT_USB_HOST -void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets) { - usbMIDITransport.tuh_midi_rx_cb(dev_addr, num_packets); +void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets) +{ } -void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t in_ep, uint8_t out_ep, uint8_t num_cables_rx, uint16_t num_cables_tx) { - printf("MIDI device address = %u, IN endpoint %u has %u cables, OUT endpoint %u has %u cables\r\n", - dev_addr, in_ep & 0xf, num_cables_rx, out_ep & 0xf, num_cables_tx); +void tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t *mount_cb_data) +{ + printf("MIDI device address = %u, IN endpoint has %u cables, OUT endpoint has %u cables\r\n", + mount_cb_data->daddr, mount_cb_data->rx_cable_count, mount_cb_data->tx_cable_count); - usbMIDITransport.midi_dev_addr = dev_addr; - - USB_Device_Type_t type = {MIDI_ID, 0, dev_addr, 0}; + USB_Device_Type_t type = {MIDI_ID, 0, mount_cb_data->daddr, 0}; usb_host_devices[total_usb_host_devices].type = type; total_usb_host_devices++; } // Invoked when device with hid interface is un-mounted -void tuh_midi_umount_cb(uint8_t dev_addr, uint8_t instance) { +void tuh_midi_umount_cb(uint8_t dev_addr, uint8_t instance) +{ printf("MIDI device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); - usbMIDITransport.midi_dev_addr = 0; // Probably should actulaly work out what was unplugged and all that total_usb_host_devices = 0; } #endif -void authentication_successful() { +void authentication_successful() +{ printf("Auth done\r\n"); authReady = true; } #if USB_HOST_STACK -USB_Device_Type_t get_device_address_for(uint8_t deviceType) { - if (deviceType == XBOXONE) { +USB_Device_Type_t get_device_address_for(uint8_t deviceType) +{ + if (deviceType == XBOXONE) + { return xone_dev_addr; } - if (deviceType == XBOX360) { + if (deviceType == XBOX360) + { return x360_dev_addr; } - if (deviceType == PS4) { + if (deviceType == PS4) + { return ps4_dev_addr; } + if (deviceType == PS5) + { + return ps5_dev_addr; + } return {0}; } #endif -void send_report_to_controller(uint8_t dev_addr, uint8_t instance, const uint8_t *report, uint8_t len) { - if (dev_addr && tuh_xinput_mounted(dev_addr, instance)) { - tuh_xinput_send_report(dev_addr, instance, report, len); +bool send_report_to_controller(uint8_t dev_addr, uint8_t instance, const uint8_t *report, uint8_t len) +{ + if (dev_addr && tuh_xinput_mounted(dev_addr, instance)) + { + return tuh_xinput_send_report(dev_addr, instance, report, len); } + return false; } -void tud_mount_cb(void) { +extern "C" void tud_mount_cb(void) +{ + printf("mounted!\r\n"); device_reset(); - connected = true; } #if USB_HOST_STACK -uint8_t get_usb_host_device_count() { +uint8_t get_usb_host_device_count() +{ return total_usb_host_devices; } -USB_Device_Type_t get_usb_host_device_type(uint8_t id) { +USB_Device_Type_t get_usb_host_device_type(uint8_t id) +{ return usb_host_devices[id].type; } -uint8_t get_usb_host_device_data(uint8_t id, uint8_t *buf) { - if (usb_host_devices[id].type.console_type == GENERIC) { +uint8_t get_usb_host_device_data(uint8_t id, uint8_t *buf) +{ + if (usb_host_devices[id].type.console_type == GENERIC) + { USB_Host_Data_t *host = (USB_Host_Data_t *)buf; fill_generic_report_host(usb_host_devices[id].type.dev_addr, usb_host_devices[id].type.instance, (uint8_t *)&usb_host_devices[id].report, host); @@ -313,8 +399,10 @@ uint8_t get_usb_host_device_data(uint8_t id, uint8_t *buf) { return usb_host_devices[id].report_length; } -uint8_t read_usb_host_devices(uint8_t *buf) { - for (int i = 0; i < total_usb_host_devices; i++) { +uint8_t read_usb_host_devices(uint8_t *buf) +{ + for (int i = 0; i < total_usb_host_devices; i++) + { USB_Device_Type_t *type = &usb_host_devices[i].type; buf[(i * 2)] = type->console_type; buf[(i * 2) + 1] = type->sub_type; @@ -322,135 +410,183 @@ uint8_t read_usb_host_devices(uint8_t *buf) { return total_usb_host_devices * 2; } -bool tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t console_type, uint8_t sub_type) { +bool tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t itf_num, uint8_t console_type, uint8_t sub_type) +{ printf("Detected controller: %d (%d) on %d, %d\r\n", console_type, sub_type, dev_addr, instance); uint16_t host_vid = 0; uint16_t host_pid = 0; tuh_vid_pid_get(dev_addr, &host_vid, &host_pid); printf("VID: %04x, PID: %04x \r\n", host_vid, host_pid); - USB_Device_Type_t type = {console_type, sub_type, dev_addr, instance}; + USB_Device_Type_t type = {console_type, sub_type, dev_addr, instance, itf_num, DRUM_UNKNOWN}; tuh_descriptor_get_device_sync(dev_addr, buf, sizeof(USB_DEVICE_DESCRIPTOR)); USB_DEVICE_DESCRIPTOR *desc = (USB_DEVICE_DESCRIPTOR *)buf; get_usb_device_type_for(host_vid, host_pid, desc->bcdDevice, &type); - switch (type.console_type) { - case XBOX360: - x360_dev_addr = type; - usb_host_devices[total_usb_host_devices].type = type; - total_usb_host_devices++; - xinput_controller_connected(host_vid, host_pid); - if (consoleType == XBOX360) { - foundXB = true; - // Reboot the controller and wait for auth - if (!xboxAuthValid) { - xboxAuthValid = true; - reset_usb(); - } - printf("found xb\r\n"); + switch (type.console_type) + { + case XBOX360: + x360_dev_addr = type; + usb_host_devices[total_usb_host_devices].type = type; + total_usb_host_devices++; + xinput_controller_connected(host_vid, host_pid); + break; + case XBOX360_W: + x360_dev_addr = type; + usb_host_devices[total_usb_host_devices].type = type; + total_usb_host_devices++; + printf("found xb360 wireless\r\n"); + send_report_to_controller(dev_addr, instance, xbox360w_prescence, sizeof(xbox360w_prescence)); + break; + case XBOXONE: + xone_dev_addr = type; + xone_controller_connected(dev_addr, instance); + usb_host_devices[total_usb_host_devices].type = type; + usb_host_devices[total_usb_host_devices].xone_init_id = 0; + total_usb_host_devices++; + if (consoleType == XBOXONE) + { + foundXB = true; + } + break; + case SANTROLLER: + { + tuh_descriptor_get_product_string_sync(dev_addr, 0, buf, sizeof(buf)); + usb_host_devices[total_usb_host_devices].type = type; + total_usb_host_devices++; + printf("Found Santroller controller\r\n"); + printf("Sub type: %d\r\n", type.sub_type); + break; + } + case RAPHNET: + { + uint8_t data[] = {0x00, 0x00, 0x00}; + uint8_t data2[] = {0x06, 0x00, 0x00}; + for (int i = 0; i < 10; i++) + { + transfer_with_usb_controller(type, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE, HID_REQUEST_SET_REPORT, 0x0300, sizeof(data2), data2, NULL); + transfer_with_usb_controller(type, USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE, HID_REQUEST_GET_REPORT, 0x0300, sizeof(data), data, NULL); + if (data[0]) + { + break; } + sleep_ms(100); + } + switch (data[2]) + { + case RNT_TYPE_PSX_DIGITAL: + case RNT_TYPE_PSX_ANALOG: + case RNT_TYPE_PSX_NEGCON: + case RNT_TYPE_PSX_MOUSE: + case RNT_TYPE_CLASSIC: + case RNT_TYPE_UDRAW_TABLET: + case RNT_TYPE_NUNCHUK: + case RNT_TYPE_CLASSIC_PRO: + type.sub_type = GAMEPAD; break; - case XBOX360_W: - x360_dev_addr = type; - usb_host_devices[total_usb_host_devices].type = type; - total_usb_host_devices++; - printf("found xb360 wireless\r\n"); - send_report_to_controller(dev_addr, instance, xbox360w_prescence, sizeof(xbox360w_prescence)); - break; - case XBOXONE: - xone_dev_addr = type; - xone_controller_connected(dev_addr, instance); - usb_host_devices[total_usb_host_devices].type = type; - usb_host_devices[total_usb_host_devices].xone_init_id = 0; - total_usb_host_devices++; - if (consoleType == XBOXONE) { - foundXB = true; - } + case RNT_TYPE_WII_GUITAR: + type.sub_type = GUITAR_HERO_GUITAR; break; - case SANTROLLER: { - tuh_descriptor_get_product_string_sync(dev_addr, 0, buf, sizeof(buf)); - usb_host_devices[total_usb_host_devices].type = type; - total_usb_host_devices++; - printf("Found Santroller controller\r\n"); - printf("Sub type: %d\r\n", type.sub_type); + case RNT_TYPE_WII_DRUM: + type.sub_type = GUITAR_HERO_DRUMS; break; } - case RAPHNET: { - uint8_t data[] = {0x00, 0x00, 0x00}; - uint8_t data2[] = {0x06, 0x00, 0x00}; - for (int i = 0; i < 10; i++) { - transfer_with_usb_controller(dev_addr, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE, HID_REQUEST_SET_REPORT, 0x0300, 1, 3, data2, NULL); - transfer_with_usb_controller(dev_addr, USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE, HID_REQUEST_GET_REPORT, 0x0300, 1, 3, data, NULL); - if (data[0]) { - break; - } - sleep_ms(100); - } - switch (data[2]) { - case RNT_TYPE_PSX_DIGITAL: - case RNT_TYPE_PSX_ANALOG: - case RNT_TYPE_PSX_NEGCON: - case RNT_TYPE_PSX_MOUSE: - case RNT_TYPE_CLASSIC: - case RNT_TYPE_UDRAW_TABLET: - case RNT_TYPE_NUNCHUK: - case RNT_TYPE_CLASSIC_PRO: - type.sub_type = GAMEPAD; - break; - case RNT_TYPE_WII_GUITAR: - type.sub_type = GUITAR_HERO_GUITAR; - break; - case RNT_TYPE_WII_DRUM: - type.sub_type = GUITAR_HERO_DRUMS; - break; - } - printf("Found Raphnet controller\r\n"); - printf("Sub type: %02x\r\n", type.sub_type); - usb_host_devices[total_usb_host_devices].type = type; - total_usb_host_devices++; - break; + printf("Found Raphnet controller\r\n"); + printf("Sub type: %02x\r\n", type.sub_type); + usb_host_devices[total_usb_host_devices].type = type; + total_usb_host_devices++; + break; + } + case XBOX360_BB: + case OG_XBOX: + case KEYBOARD: + case MOUSE: + case STREAM_DECK: + case UNKNOWN: + case GENERIC: + case STEPMANIAX: + case LTEK: + case LTEK_ID: + case XINPUTCOMPAT: + case STADIA: + printf("Found Generic controller\r\n"); + usb_host_devices[total_usb_host_devices].type = type; + total_usb_host_devices++; + break; + case SWITCH: + { + printf("Found Switch controller\r\n"); + usb_host_devices[total_usb_host_devices].type = type; + usb_host_devices[total_usb_host_devices].switch_sent_timeout = false; + total_usb_host_devices++; + uint8_t buf[2] = {0x80 /* PROCON_REPORT_SEND_USB */, 0x02 /* PROCON_USB_HANDSHAKE */}; + send_report_to_controller(dev_addr, instance, buf, 2); + break; + } + case SWITCH2: + printf("Found Switch 2 controller\r\n"); + usb_host_devices[total_usb_host_devices].type = type; + usb_host_devices[total_usb_host_devices].switch_sent_timeout = false; + total_usb_host_devices++; + if (type.sub_type == NON_CONTROLLER) + { + uint8_t buf[] = {0x03, 0x91, 0x00, 0x0d, 0x00, 0x08, + 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + send_report_to_controller(dev_addr, instance, buf, sizeof(buf)); } - case XBOX360_BB: - case OG_XBOX: - case KEYBOARD: - case MOUSE: - case STREAM_DECK: - case PS5: - case SWITCH: - case UNKNOWN: - case GENERIC: - case STEPMANIAX: - case LTEK: - case LTEK_ID: - case XINPUTCOMPAT: - case STADIA: - printf("Found Generic controller\r\n"); - usb_host_devices[total_usb_host_devices].type = type; - total_usb_host_devices++; - break; - case PS3: - // GHWT and GH5 guitars have the same vid and pid, but different tap bar functions. We can read the device name to actually determine what it is - if (type.sub_type == GUITAR_HERO_GUITAR && XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(dev_addr, 0, buf, sizeof(buf))) { - uint16_t wtProduct[] = {'G', 'u', 'i', 't', 'a', 'r', ' ', 'H', 'e', 'r', 'o', '4'}; - if (memcmp(wtProduct, buf, sizeof(wtProduct)) || memcmp(wtProduct, buf + 1, sizeof(wtProduct))) { - type.sub_type = GUITAR_HERO_GUITAR_WT; - } - } - usb_host_devices[total_usb_host_devices].type = type; - usb_host_devices[total_usb_host_devices].xone_init_id = millis(); - total_usb_host_devices++; - printf("Found PS3 controller\r\n"); - printf("Sub type: %d\r\n", type.sub_type); - ps3_controller_connected(dev_addr, host_vid, host_pid); - break; - case PS4: - usb_host_devices[total_usb_host_devices].type = type; - total_usb_host_devices++; - if (!ps4_dev_addr.dev_addr) { - ps4_dev_addr = type; - - printf("Found PS4 controller\r\n"); - ps4_controller_connected(dev_addr, host_vid, host_pid); + break; + + case PS3: + // GHWT and GH5 guitars have the same vid and pid, but different tap bar functions. We can read the device name to actually determine what it is + if (type.sub_type == GUITAR_HERO_GUITAR && XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(dev_addr, 0, buf, sizeof(buf))) + { + uint16_t wtProduct[] = {'G', 'u', 'i', 't', 'a', 'r', ' ', 'H', 'e', 'r', 'o', '4'}; + if (memcmp(wtProduct, buf, sizeof(wtProduct)) == 0 || memcmp(wtProduct, buf + 1, sizeof(wtProduct)) == 0) + { + type.sub_type = GUITAR_HERO_GUITAR_WT; } - break; + } + usb_host_devices[total_usb_host_devices].type = type; + usb_host_devices[total_usb_host_devices].xone_init_id = millis(); + total_usb_host_devices++; + printf("Found PS3 controller\r\n"); + printf("Sub type: %d\r\n", type.sub_type); + ps3_controller_connected(dev_addr, host_vid, host_pid); + + if (host_vid == SONY_VID && host_pid == SONY_DS3_PID) + { + // Enable PS3 reports + uint8_t hid_command_enable[] = {0x42, 0x0c, 0x00, 0x00}; + transfer_with_usb_controller(type, (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_SET_REPORT, 0x03F4, sizeof(hid_command_enable), hid_command_enable, NULL); + handle_player_leds(0); + } + break; + case PS4: + usb_host_devices[total_usb_host_devices].type = type; + total_usb_host_devices++; + if (consoleType == PS4 && !ps4_dev_addr.dev_addr) + { + ps4_dev_addr = type; + + printf("Found PS4 controller\r\n"); + ps4_controller_connected(dev_addr, host_vid, host_pid); + } + break; + case PS5: + usb_host_devices[total_usb_host_devices].type = type; + total_usb_host_devices++; + // assume ps5 auth if p5general is plugged in + if (consoleType == PS4 && host_vid == 0x2b81 && host_pid == 0x0101) + { + consoleType = PS5; + reset_usb(); + } + if (consoleType == PS5 && !ps5_dev_addr.dev_addr) + { + ps5_dev_addr = type; + + printf("Found PS5 controller\r\n"); + ps4_controller_connected(dev_addr, host_vid, host_pid); + } + break; } printf("Total devices: %d\r\n", total_usb_host_devices); @@ -458,174 +594,292 @@ bool tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t console_typ return true; } -void tuh_xinput_umount_cb(uint8_t dev_addr, uint8_t instance) { +void tuh_xinput_umount_cb(uint8_t dev_addr, uint8_t instance) +{ printf("Unplugged %d\r\n", dev_addr); - if (xone_dev_addr.dev_addr == dev_addr && xone_dev_addr.instance == instance) { + if (xone_dev_addr.dev_addr == dev_addr && xone_dev_addr.instance == instance) + { xone_dev_addr.dev_addr = 0; } - if (x360_dev_addr.dev_addr == dev_addr && x360_dev_addr.instance == instance) { + if (x360_dev_addr.dev_addr == dev_addr && x360_dev_addr.instance == instance) + { x360_dev_addr.dev_addr = 0; } - if (ps4_dev_addr.dev_addr == dev_addr && ps4_dev_addr.instance == instance) { + if (ps4_dev_addr.dev_addr == dev_addr && ps4_dev_addr.instance == instance) + { ps4_dev_addr.dev_addr = 0; ps4_controller_disconnected(); } // Probably should actulaly work out what was unplugged and all that total_usb_host_devices = 0; } -bool wasXb1Input = false; -void tuh_xinput_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { +void tuh_xinput_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) +{ // If there are xb1 init packets to send, send them - for (int i = 0; i < total_usb_host_devices; i++) { - if (usb_host_devices[i].type.dev_addr == dev_addr && usb_host_devices[i].type.instance == instance) { - if (usb_host_devices[i].type.console_type == XBOXONE) { - if (xone_controller_send_init_packet(dev_addr, instance, usb_host_devices[i].xone_init_id)) { + for (int i = 0; i < total_usb_host_devices; i++) + { + if (usb_host_devices[i].type.dev_addr == dev_addr && usb_host_devices[i].type.instance == instance) + { + if (usb_host_devices[i].type.console_type == XBOXONE) + { + if (xone_controller_send_init_packet(dev_addr, instance, usb_host_devices[i].xone_init_id)) + { usb_host_devices[i].xone_init_id++; } } + if (usb_host_devices[i].type.console_type == SWITCH2 && usb_host_devices[i].type.sub_type == NON_CONTROLLER) + { + if (!usb_host_devices[i].switch_sent_timeout) + { + usb_host_devices[i].switch_sent_timeout = true; + uint8_t buf[] = {0x09, 0x91, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0}; + send_report_to_controller(dev_addr, instance, buf, sizeof(buf)); + } + } } } } long lastPlayerLed = 0; long lastWakeup = 0; -void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { - if (!len) { +void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) +{ + if (!len) + { // Skip processing a null report, assume it is corrupted return; } - if (dev_addr == xone_dev_addr.dev_addr && instance == xone_dev_addr.instance) { + if (dev_addr == xone_dev_addr.dev_addr && instance == xone_dev_addr.instance) + { receive_report_from_controller(report, len); } + // receive report from p5general and forward it to the console + if (dev_addr == ps5_dev_addr.dev_addr && instance == ps5_dev_addr.instance) + { + hash_pending = false; + tud_xusb_n_report(0, report, len); + return; + } // Send player indicator every 10 seconds or so just as a keep alive - if (millis() - lastPlayerLed > 10000) { + if (millis() - lastPlayerLed > 10000) + { handle_player_leds(0); lastPlayerLed = millis(); } - for (int i = 0; i < total_usb_host_devices; i++) { - if (usb_host_devices[i].type.dev_addr == dev_addr && usb_host_devices[i].type.instance == instance) { - if (usb_host_devices[i].type.console_type == XBOXONE) { + for (int i = 0; i < total_usb_host_devices; i++) + { + if (usb_host_devices[i].type.dev_addr == dev_addr && usb_host_devices[i].type.instance == instance) + { + if (usb_host_devices[i].type.console_type == XBOXONE) + { GipHeader_t *header = (GipHeader_t *)report; - if (header->command == GIP_VIRTUAL_KEYCODE) { + if (header->command == GIP_VIRTUAL_KEYCODE) + { GipKeystroke_t *keystroke = (GipKeystroke_t *)report; - if (wasXb1Input) { - XboxOneInputHeader_Data_t *gamepad = (XboxOneInputHeader_Data_t *)(&(usb_host_devices[i].report)); - gamepad->guide = keystroke->pressed; - } - return; + usb_host_devices[i].type.xone_guide = keystroke->pressed; + continue; } - if (header->command != GHL_HID_REPORT && header->command != GIP_INPUT_REPORT) { - return; + if (header->command != GHL_HID_REPORT && header->command != GIP_INPUT_REPORT) + { + continue; } - wasXb1Input = header->command == GIP_INPUT_REPORT; } - if ((millis() - usb_host_devices[i].xone_init_id) < 5000) { - if (usb_host_devices[i].type.console_type == PS3 && usb_host_devices[i].type.sub_type == ROCK_BAND_PRO_KEYS) { + if ((millis() - usb_host_devices[i].xone_init_id) < 5000) + { + if (usb_host_devices[i].type.console_type == PS3 && (usb_host_devices[i].type.sub_type == ROCK_BAND_PRO_KEYS || usb_host_devices[i].type.sub_type == ROCK_BAND_PRO_GUITAR_MUSTANG || usb_host_devices[i].type.sub_type == ROCK_BAND_PRO_GUITAR_SQUIRE)) + { uint8_t hid_command_enable[40] = { 0xE9, 0x00, 0x89, 0x1B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - transfer_with_usb_controller(dev_addr, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS, HID_REQUEST_SET_REPORT, 0x0300, 0, sizeof(hid_command_enable), hid_command_enable, NULL); + transfer_with_usb_controller(usb_host_devices[i].type, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS, HID_REQUEST_SET_REPORT, 0x0300, sizeof(hid_command_enable), hid_command_enable, NULL); } } - if (usb_host_devices[i].type.console_type == XBOX360_W) { + if (usb_host_devices[i].type.console_type == XBOX360_W) + { // Corrupt report, ignore - if (len < sizeof(XBOX_WIRELESS_HEADER)) { - return; + if (len < sizeof(XBOX_WIRELESS_HEADER)) + { + continue; } XBOX_WIRELESS_HEADER *header = (XBOX_WIRELESS_HEADER *)report; - if (header->id == 0x08) { + if (header->id == 0x08) + { // Disconnected - if (header->type == 0x00) { + if (header->type == 0x00) + { usb_host_devices[i].type.sub_type = UNKNOWN; printf("Disconnected\r\n", dev_addr, instance); } - } else if (header->id == 0x00) { + } + else if (header->id == 0x00) + { // Gamepad inputs - if (header->type == 0x01 || header->type == 0x03) { + if (header->type == 0x01 || header->type == 0x03) + { memcpy(&usb_host_devices[i].report, report + sizeof(header), len - sizeof(header)); usb_host_devices[i].report_length = len - sizeof(header); - if (usb_host_devices[i].type.sub_type == XINPUT_DRUMS) { + if (usb_host_devices[i].type.sub_type == XINPUT_DRUMS && usb_host_devices[i].type.drum_type == DRUM_UNKNOWN) + { XInputGamepad_Data_t *gamepad = (XInputGamepad_Data_t *)&usb_host_devices[i].report; - if (gamepad->leftThumbClick) { - usb_host_devices[i].type.sub_type = XINPUT_GH_DRUMS; - } else { - usb_host_devices[i].type.sub_type = XINPUT_RB_DRUMS; + if (gamepad->leftThumbClick) + { + usb_host_devices[i].type.drum_type = DRUM_GH; + } + else + { + // Only RB2/3 kits are wireless + usb_host_devices[i].type.drum_type = DRUM_RB2; } } + if ((usb_host_devices[i].type.sub_type == XINPUT_GUITAR_ALTERNATE || usb_host_devices[i].type.sub_type == XINPUT_PRO_GUITAR) && usb_host_devices[i].type.drum_type == GUITAR_CHECK) + { + // request capabilities + send_report_to_controller(dev_addr, instance, capabilitiesRequest, sizeof(capabilitiesRequest)); + usb_host_devices[i].type.drum_type == DRUM_UNKNOWN; + } } // Link report - if (header->type == 0x0f) { + if (header->type == 0x0f) + { XBOX_WIRELESS_LINK_REPORT *linkReport = (XBOX_WIRELESS_LINK_REPORT *)report; - if (linkReport->always_0xCC != 0xCC) { - return; + if (linkReport->always_0xCC != 0xCC) + { + continue; } uint8_t sub_type = linkReport->subtype & ~0x80; usb_host_devices[i].type.sub_type = sub_type; printf("Found subtype: %02x %02x %02x\r\n", sub_type, dev_addr, instance); xinput_w_controller_connected(); // Request capabilities so we can figure out WT guitars - if (sub_type == XINPUT_GUITAR_ALTERNATE) { - // request capabilities - send_report_to_controller(dev_addr, instance, capabilitiesRequest, sizeof(capabilitiesRequest)); + if (sub_type == XINPUT_GUITAR_ALTERNATE || sub_type == XINPUT_PRO_GUITAR) + { + usb_host_devices[i].type.drum_type = GUITAR_CHECK; } } - if (header->type == 0x05) { + // Capabilities report + if (header->type == 0x05) + { XBOX_WIRELESS_CAPABILITIES *caps = (XBOX_WIRELESS_CAPABILITIES *)report; - if (caps->always_0x12 != 0x12) { - return; + if (caps->always_0x12 != 0x12) + { + continue; } printf("Found capabilities: %02x %02x\r\n", dev_addr, instance); - if (caps->leftStickX == 0xFFC0 && caps->rightStickX == 0xFFC0) { + if (caps->leftStickX == 0xFFC0 && caps->rightStickX == 0xFFC0) + { usb_host_devices[i].type.sub_type = XINPUT_GUITAR_WT; printf("Found wt\r\n"); } + + if (DEVICE_TYPE_IS_PRO_GUITAR && proGuitarType != ROCK_BAND_PRO_GUITAR_MUSTANG && (caps->leftStickY == XBOX_360_MUSTANG_PID || caps->leftStickY == XBOX_360_MUSTANG_MPA_PID) ) { + proGuitarType = ROCK_BAND_PRO_GUITAR_MUSTANG; + reset_usb(); + } + + if (DEVICE_TYPE_IS_PRO_GUITAR && proGuitarType != ROCK_BAND_PRO_GUITAR_SQUIRE && caps->leftStickY == XBOX_360_SQUIRE_MPA_PID) { + proGuitarType = ROCK_BAND_PRO_GUITAR_SQUIRE; + reset_usb(); + } } } - return; + continue; + } + if (usb_host_devices[i].type.console_type == STREAM_DECK && report[0] != STREAM_DECK_INPUT_REPORT_ID) + { + continue; } - if (usb_host_devices[i].type.console_type == STREAM_DECK && report[0] != STREAM_DECK_INPUT_REPORT_ID) { + if (usb_host_devices[i].type.console_type == PS5 && report[0] != PS5_INPUT_REPORT_ID) + { continue; } - if (usb_host_devices[i].type.console_type == PS5 && report[0] != PS5_INPUT_REPORT_ID) { + if (usb_host_devices[i].type.console_type == STEPMANIAX && report[0] != STEPMANIA_X_REPORT_ID) + { continue; } - if (usb_host_devices[i].type.console_type == STEPMANIAX && report[0] != STEPMANIA_X_REPORT_ID) { + if (usb_host_devices[i].type.console_type == STADIA && report[0] != STADIA_REPORT_ID) + { continue; } - if (usb_host_devices[i].type.console_type == STADIA && report[0] != STADIA_REPORT_ID) { + if (usb_host_devices[i].type.console_type == SWITCH2 && usb_host_devices[i].type.sub_type == NON_CONTROLLER) + { continue; } - if (usb_host_devices[i].type.console_type == SWITCH && usb_host_devices[i].type.sub_type == GAMEPAD) { - if (!usb_host_devices[i].switch_sent_handshake) { - usb_host_devices[i].switch_sent_handshake = true; + if (usb_host_devices[i].type.console_type == SWITCH && usb_host_devices[i].type.sub_type == GAMEPAD) + { + if (!usb_host_devices[i].switch_sent_timeout && report[0] == 0x81 && report[1] == 0x02 /* PROCON_USB_HANDSHAKE */) + { + usb_host_devices[i].switch_sent_timeout = true; + uint8_t buf[2] = {0x80 /* PROCON_REPORT_SEND_USB */, 0x03 /* HIGH SPEED */}; + send_report_to_controller(dev_addr, instance, buf, 2); + continue; + } + else if (report[0] == 0x81 && report[1] == 0x03 /* HIGH SPEED */) + { uint8_t buf[2] = {0x80 /* PROCON_REPORT_SEND_USB */, 0x02 /* PROCON_USB_HANDSHAKE */}; send_report_to_controller(dev_addr, instance, buf, 2); - } else if (!usb_host_devices[i].switch_sent_timeout) { - usb_host_devices[i].switch_sent_timeout = true; + continue; + } + else if (report[0] == 0x81 && report[1] == 0x02 /* PROCON_USB_HANDSHAKE */) + { uint8_t buf[2] = {0x80 /* PROCON_REPORT_SEND_USB */, 0x04 /* PROCON_USB_ENABLE */}; send_report_to_controller(dev_addr, instance, buf, 2); + continue; + } + if (report[0] != SWITCH_PRO_CON_FULL_REPORT_ID) + { + continue; } + } + if (usb_host_devices[i].type.console_type == SWITCH2 && usb_host_devices[i].type.sub_type == GAMEPAD) + { + if (report[0] != SWITCH_2_GC_FULL_REPORT_ID && report[0] != SWITCH_2_PRO_CON_FULL_REPORT_ID) + { + continue; + } + } + if (usb_host_devices[i].type.console_type == XBOX360) + { - if (report[0] != SWITCH_PRO_CON_FULL_REPORT_ID) { + XInputGamepad_Data_t *gamepad = (XInputGamepad_Data_t *)report; + // Drop any corrupted or invalid packets + // crkd xbox guitars send extra bytes so we have to account for that. + if (gamepad->rsize != sizeof(XInputGamepad_Data_t) || (len != sizeof(XInputGamepad_Data_t) && len != 26)) + { continue; } } + if (usb_host_devices[i].type.console_type == PS3 && usb_host_devices[i].type.sub_type == ROCK_BAND_GUITAR) + { + PS3RockBandGuitar_Data_t *guitar = (PS3RockBandGuitar_Data_t *)report; + // ignore neutral value from whammy and pickup + if (guitar->whammy != 0x7F) + { + usb_host_devices[i].type.whammy = guitar->whammy; + } + if (guitar->pickup != 0x7F) + { + usb_host_devices[i].type.pickup = guitar->pickup; + } + } memcpy(&usb_host_devices[i].report, report, len); usb_host_devices[i].report_length = len; - if (usb_host_devices[i].type.console_type == XBOX360 && usb_host_devices[i].type.sub_type == XINPUT_DRUMS) { - XInputGamepad_Data_t *gamepad = (XInputGamepad_Data_t *)&usb_host_devices[i].report; - if (gamepad->rsize == sizeof(XInputGamepad_Data_t)) { - if (gamepad->leftThumbClick) { - usb_host_devices[i].type.sub_type = XINPUT_GH_DRUMS; - } else { - usb_host_devices[i].type.sub_type = XINPUT_RB_DRUMS; - } + // Xinput drum detection + if (usb_host_devices[i].type.console_type == XBOX360 && usb_host_devices[i].type.sub_type == XINPUT_DRUMS && usb_host_devices[i].type.drum_type == DRUM_UNKNOWN) + { + XInputRockBandDrums_Data_t *drums = (XInputRockBandDrums_Data_t *)&usb_host_devices[i].report; + if (drums->leftThumbClick) + { + usb_host_devices[i].type.drum_type = DRUM_GH; + } + else + { + // Only RB1 kits are wired + usb_host_devices[i].type.drum_type = DRUM_RB1; } } - return; } } } @@ -650,40 +904,50 @@ usbh_class_driver_t driver_host[] = { .xfer_cb = midih_xfer_cb, .close = midih_close}}; -usbh_class_driver_t const *usbh_app_driver_get_cb(uint8_t *driver_count) { +usbh_class_driver_t const *usbh_app_driver_get_cb(uint8_t *driver_count) +{ *driver_count = 2; return driver_host; } #endif -uint8_t const *tud_descriptor_device_cb(void) { +uint8_t const *tud_descriptor_device_cb(void) +{ descriptorRequest(USB_DESCRIPTOR_DEVICE << 8, 0, buf); return buf; } -uint8_t const *tud_hid_custom_descriptor_report_cb(uint8_t instance) { +uint8_t const *tud_hid_custom_descriptor_report_cb(uint8_t instance) +{ descriptorRequest(HID_DESCRIPTOR_REPORT << 8, instance, buf); return buf; } -uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { - (void)index; // for multiple configurations +uint8_t const *tud_descriptor_configuration_cb(uint8_t index) +{ + (void)index; // for multiple configurations descriptorRequest(USB_DESCRIPTOR_CONFIGURATION << 8, index, buf); return buf; } -uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { +uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ // Arduinos handle their own serial descriptor, so theres no point in sharing an implementation there. - if (index == 3) { + if (index == 3) + { return (uint16_t *)&serialstring; } - if (descriptorRequest(USB_DESCRIPTOR_STRING << 8 | index, 0, buf)) { + if (descriptorRequest(USB_DESCRIPTOR_STRING << 8 | index, 0, buf)) + { return (uint16_t *)buf; } return NULL; } -uint32_t transfer_with_usb_controller(const uint8_t dev_addr, const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t wLength, uint8_t *buffer, bool *status) { - if (!dev_addr) { +uint32_t transfer_with_usb_controller(const USB_Device_Type_t dev, const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wLength, uint8_t *buffer, bool *status) +{ + if (!dev.dev_addr) + { // Device is not connected yet! - if (status) { + if (status) + { *status = false; } return 0; @@ -692,19 +956,21 @@ uint32_t transfer_with_usb_controller(const uint8_t dev_addr, const uint8_t requ bmRequestType : requestType, bRequest : request, wValue : wValue, - wIndex : wIndex, + wIndex : dev.interface, wLength : wLength }; tuh_xfer_t xfer = {}; - xfer.daddr = dev_addr; + xfer.daddr = dev.dev_addr; xfer.ep_addr = 0; xfer.setup = &setup; xfer.buffer = buffer; xfer.complete_cb = NULL; xfer.user_data = 0; tuh_control_xfer(&xfer); - if (xfer.result != XFER_RESULT_SUCCESS) { - if (status) { + if (xfer.result != XFER_RESULT_SUCCESS) + { + if (status) + { *status = false; } return false; @@ -712,42 +978,58 @@ uint32_t transfer_with_usb_controller(const uint8_t dev_addr, const uint8_t requ return xfer.actual_len; } tusb_control_request_t lastreq; -bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { - if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_GET_DESCRIPTOR) { +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) +{ + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_GET_DESCRIPTOR) + { //------------- STD Request -------------// - if (stage == CONTROL_STAGE_SETUP) { + if (stage == CONTROL_STAGE_SETUP) + { uint8_t const desc_type = tu_u16_high(request->wValue); // uint8_t const desc_index = tu_u16_low (request->wValue); - if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESCRIPTOR_HID) { + if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESCRIPTOR_HID) + { uint16_t len = descriptorRequest(HID_DESCRIPTOR_HID << 8, request->wIndex, buf); TU_VERIFY(tud_control_xfer(rhport, request, buf, len)); return true; - } else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESCRIPTOR_REPORT) { + } + else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESCRIPTOR_REPORT) + { uint16_t len = descriptorRequest(HID_DESCRIPTOR_REPORT << 8, request->wIndex, buf); TU_VERIFY(tud_control_xfer(rhport, request, buf, len)); return true; - } else { - return false; // stall unsupported request + } + else + { + return false; // stall unsupported request } } } - if (controlRequestValid(request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength)) { + if (controlRequestValid(request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength)) + { bool status = true; - if (request->bmRequestType_bit.direction == TUSB_DIR_IN) { - if (stage == CONTROL_STAGE_SETUP) { + if (request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + if (stage == CONTROL_STAGE_SETUP) + { uint16_t len = controlRequest(request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength, buf, &status); tud_control_xfer(rhport, request, buf, len); } - } else { - if (stage == CONTROL_STAGE_SETUP) { + } + else + { + if (stage == CONTROL_STAGE_SETUP) + { tud_control_xfer(rhport, request, buf, request->wLength); } - if (stage == CONTROL_STAGE_DATA || (stage == CONTROL_STAGE_SETUP && !request->wLength)) { + if (stage == CONTROL_STAGE_DATA || (stage == CONTROL_STAGE_SETUP && !request->wLength)) + { uint8_t ret = controlRequest(request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength, buf, &status); } } - if (!status) { + if (!status) + { return status; } } @@ -767,21 +1049,27 @@ usbd_class_driver_t driver[] = { .xfer_cb = xinputd_xfer_cb, .sof = NULL}}; -usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) { +usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) +{ *driver_count = 1; return driver; } -void reboot(void) { +void reboot(void) +{ watchdog_enable(1, false); - for (;;) { + for (;;) + { } } -void bootloader(void) { +void bootloader(void) +{ reset_usb_boot(0, 0); } -void reset_usb(void) { +void reset_usb(void) +{ persistedConsoleType = consoleType; persistedConsoleTypeValid = PERSISTED_CONSOLE_TYPE_VALID; + persistedProGuitarType = proGuitarType; reboot(); } \ No newline at end of file diff --git a/src/pico/midi.cpp b/src/pico/midi.cpp new file mode 100644 index 000000000..963472b64 --- /dev/null +++ b/src/pico/midi.cpp @@ -0,0 +1,310 @@ +#include "midi.hpp" +#include "config.h" +#include "shared_main.h" +MidiDevice::MidiDevice(bool usbBased, Midi_Data_t *data) : usbBased(usbBased), midiData(data) +{ + tu_memclr(&ep_stream, sizeof(ep_stream)); + tu_edpt_stream_init(&ep_stream.rx, true, false, false, + ep_stream.rx_ff_buf, 512, m_ep_in_buf); + tu_edpt_stream_init(&ep_stream.tx, true, true, false, + ep_stream.tx_ff_buf, 512, m_ep_out_buf); + memset(cable_status, 0, sizeof(cable_status)); +} + +MidiDevice::~MidiDevice() +{ + tu_edpt_stream_deinit(&ep_stream.rx); + tu_edpt_stream_deinit(&ep_stream.tx); +} + +void MidiDevice::processMidiData(uint8_t *data, uint16_t len) +{ + tu_edpt_stream_t *ep_str_rx = &ep_stream.rx; + memcpy(ep_str_rx->ep_buf, data, len); + tu_edpt_stream_read_xfer_complete(ep_str_rx, len); +} +void MidiDevice::update(bool full_poll, bool send_events) +{ + uint8_t one_byte; + if (!tu_edpt_stream_peek(&ep_stream.rx, &one_byte)) + { + return; + } + cable_state_t *cable_state = &cable_status[0]; + uint8_t usb_packet[4]; + while (tu_edpt_stream_peek(&ep_stream.rx, &one_byte)) + { + if (!usb_pos && usbBased) + { + tu_fifo_peek_n(&ep_stream.rx.ff, usb_packet, 4); + if (tu_mem_is_zero(usb_packet, 4)) + { + // no data, just empty packet, so skip it + tu_edpt_stream_read(&ep_stream.rx, usb_packet, 4); + continue; + } + // read cable number + uint8_t p_cable_num; + tu_edpt_stream_read(&ep_stream.rx, &p_cable_num, 1); + cable_state = &cable_status[(p_cable_num >> 4) & 0x0f]; + usb_pos++; + continue; + } + else if (cable_state->pos == 0) + { + tu_edpt_stream_read(&ep_stream.rx, cable_state->data, 1); + cable_state->pos++; + uint8_t status = cable_state->data[0]; + if (status == MIDI_STATUS_SYSEX_START) + { + cable_state->sysex_in_progress = true; + // we don't know the actual size of the message yet + cable_state->actual_size = 0xFF; + } + // Running status + if (status <= MIDI_MAX_DATA_VAL) + { + // The status byte is reused, so shift the packet and insert it back + status = cable_state->status; + cable_state->data[1] = cable_state->data[0]; + cable_state->data[0] = status; + cable_state->pos++; + } + if (status < MIDI_STATUS_SYSEX_START) + { + // then it is a channel message either three bytes or two + uint8_t fake_cin = (status & 0xf0) >> 4; + switch (fake_cin) + { + case MIDI_CIN_NOTE_OFF: + case MIDI_CIN_NOTE_ON: + cable_state->actual_size = 3; + break; + case MIDI_CIN_CONTROL_CHANGE: + cable_state->actual_size = 3; + break; + case MIDI_CIN_PITCH_BEND_CHANGE: + cable_state->actual_size = 3; + break; + case MIDI_CIN_POLY_KEYPRESS: + cable_state->actual_size = 3; + break; + case MIDI_CIN_PROGRAM_CHANGE: + case MIDI_CIN_CHANNEL_PRESSURE: + cable_state->actual_size = 2; + break; + default: + break; // Should not get this + } + cable_state->sysex_in_progress = false; + } + else if (status < MIDI_STATUS_SYSREAL_TIMING_CLOCK) + { + switch (status) + { + case MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME: + case MIDI_STATUS_SYSCOM_SONG_SELECT: + cable_state->actual_size = 2; + break; + case MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER: + cable_state->actual_size = 3; + break; + case MIDI_STATUS_SYSCOM_TUNE_REQUEST: + case MIDI_STATUS_SYSEX_END: + cable_state->actual_size = 1; + break; + default: + break; + } + cable_state->sysex_in_progress = false; + } + else + { + cable_state->actual_size = 1; + cable_state->sysex_in_progress = false; + } + if (status < MIDI_STATUS_SYSEX_START) + { + cable_state->status = status; + } + } + else + { + uint8_t d; + tu_edpt_stream_read(&ep_stream.rx, &d, 1); + if (d <= MIDI_MAX_DATA_VAL) + { + if (cable_state->pos < sizeof(cable_state->data)) + { + cable_state->data[cable_state->pos] = d; + } + cable_state->pos++; + } + else if (d == MIDI_STATUS_SYSEX_END) + { + if (cable_state->pos < sizeof(cable_state->data)) + { + cable_state->data[cable_state->pos] = d; + } + cable_state->pos++; + cable_state->sysex_in_progress = false; + cable_state->actual_size = cable_state->pos; + } + else + { + // at this point this is probably a realtime message + // interleaved in the middle of a sysex message + // and we don't care about that right now + // so we ignore it + } + if (cable_state->sysex_in_progress && cable_state->pos >= sizeof(cable_state->data)) + { + // No 0xF7 yet after filling the whole buffer - drop this message instead of + // treating it as "complete" once pos catches up to the 0xFF sentinel. + cable_state->pos = 0; + cable_state->actual_size = 0; + cable_state->sysex_in_progress = false; + continue; + } + } + usb_pos++; + if (cable_state->actual_size && cable_state->pos >= cable_state->actual_size) + { + // then this is the last byte of the message, so reset pos for next message + cable_state->pos = 0; + // lets not send timing clock signals to the monitor + if (cable_state->data[0] != MIDI_STATUS_SYSREAL_TIMING_CLOCK) + { + uint8_t data_size = MIN(32, cable_state->actual_size); + // proto_Event event = {which_event : proto_Event_midiDebug_tag, event : {midiDebug : {data : {size : data_size, bytes : {0}}}}}; + // memcpy(event.event.midiDebug.data.bytes, cable_state->data, data_size); + // HIDConfigDevice::send_event(event, false); + // printf("data: "); + // for (uint8_t i = 0; i < data_size; i++) { + // printf("%02X ", cable_state->data[i]); + // } + // printf("\r\n"); + } + uint8_t status = (cable_state->data[0] & 0xf0) >> 4; + uint8_t channel = cable_state->data[0] & 0x0f; + switch (status) + { + case MIDI_CIN_NOTE_OFF: + offNote(channel, cable_state->data[1], 0); + break; + case MIDI_CIN_NOTE_ON: + onNote(channel, cable_state->data[1], cable_state->data[2]); + break; + case MIDI_CIN_CONTROL_CHANGE: + onControlChange(channel, cable_state->data[1], cable_state->data[2]); + break; + case MIDI_CIN_PITCH_BEND_CHANGE: + onPitchBend(channel, ((int16_t)cable_state->data[3] << 7) | cable_state->data[2]); + break; + case MIDI_CIN_POLY_KEYPRESS: + break; + case MIDI_CIN_PROGRAM_CHANGE: + case MIDI_CIN_CHANNEL_PRESSURE: + break; + default: + break; + } + if (cable_state->data[0] < MIDI_STATUS_SYSEX_START) + { + // if (seenChannels.find({m_id, channel}) == seenChannels.end()) + // { + // if (HIDConfigDevice::tool_closed()) + // { + // printf("Seen new MIDI channel: %d on device %d\r\n", channel, m_id); + // seenChannels.insert_or_assign({m_id, channel}, true); + // reload(); + // } + // } + } + if (cable_state->data[0] == MIDI_STATUS_SYSEX_START) + { + uint8_t buttons_header[] = {MIDI_STATUS_SYSEX_START, 0x08, 0x40}; + if (memcmp(cable_state->data, buttons_header, sizeof(buttons_header)) == 0) + { + // if (seenChannels.find({m_id, MIDI_CHANNEL_PROGUITAR}) == seenChannels.end()) + // { + // printf("Seen new MIDI channel: proguitar on device %d\r\n", m_id); + // seenChannels[{m_id, MIDI_CHANNEL_PROGUITAR}] = true; + // if (HIDConfigDevice::tool_closed()) + // { + // reload(); + // } + // } + + if (cable_state->data[3] == MIDI_SYSEX_ID_PROGUITAR_MUSTANG && DEVICE_TYPE_IS_PRO_GUITAR && proGuitarType != ROCK_BAND_PRO_GUITAR_MUSTANG) + { + proGuitarType = ROCK_BAND_PRO_GUITAR_MUSTANG; + reset_usb(); + } + if (cable_state->data[3] == MIDI_SYSEX_ID_PROGUITAR_SQUIER && DEVICE_TYPE_IS_PRO_GUITAR && proGuitarType != ROCK_BAND_PRO_GUITAR_SQUIRE) + { + proGuitarType = ROCK_BAND_PRO_GUITAR_SQUIRE; + reset_usb(); + } + midiData->seenProGuitar = true; + if (cable_state->data[4] == 0x08) + { + // button events + memcpy(&midiData->proGuitarData, cable_state->data, sizeof(midiData->proGuitarData)); + } + if (cable_state->data[4] == 0x01) + { + // fret state events + uint8_t string = cable_state->data[5] - 1; + switch (string) + { + case 0: + midiData->midiFrets[string] = cable_state->data[6] - 0x40; + break; + case 1: + midiData->midiFrets[string] = cable_state->data[6] - 0x3B; + break; + case 2: + midiData->midiFrets[string] = cable_state->data[6] - 0x37; + break; + case 3: + midiData->midiFrets[string] = cable_state->data[6] - 0x32; + break; + case 4: + midiData->midiFrets[string] = cable_state->data[6] - 0x2D; + break; + case 5: + midiData->midiFrets[string] = cable_state->data[6] - 0x28; + break; + default: + break; + } + } + if (cable_state->data[4] == 0x05) + { + // picking events + uint8_t string = cable_state->data[5] - 1; + uint8_t velocity = cable_state->data[6]; + if (midiData->midiStringVelocities[string] == velocity) + { + velocity ^= 1; + } + midiData->midiStringVelocities[string] = velocity; + } + } + } + // at this point we can look at the state and process the message. + if (usb_pos < USB_PACKET_SIZE && usbBased) + { + // discard the unused bytes in the USB packet if we haven't already read them + tu_edpt_stream_read(&ep_stream.rx, cable_state->data, USB_PACKET_SIZE - usb_pos); + } + usb_pos = 0; + } + if (usb_pos >= USB_PACKET_SIZE) + { + // then this is the end of the USB packet, so reset usb_pos for next packet + usb_pos = 0; + } + } +} \ No newline at end of file diff --git a/src/pico/midi_host.c b/src/pico/midi_host.c deleted file mode 100644 index 9d856e2d3..000000000 --- a/src/pico/midi_host.c +++ /dev/null @@ -1,847 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb_option.h" - -#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_MIDI) - -#include "host/usbh.h" -#include "host/usbh_pvt.h" -#include "midi_host.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -#ifndef CFG_TUH_MAX_CABLES -#define CFG_TUH_MAX_CABLES 16 -#endif -#define CFG_TUH_MIDI_RX_BUFSIZE 64 -#define CFG_TUH_MIDI_TX_BUFSIZE 64 -#ifndef CFG_TUH_MIDI_EP_BUFSIZE -#define CFG_TUH_MIDI_EP_BUFSIZE 64 -#endif - -#define MIDI_CS_ROLAND_HEADER 0xF1 - -// TODO: refactor to share code with the MIDI Device driver -typedef struct -{ - uint8_t buffer[4]; - uint8_t index; - uint8_t total; -} midi_stream_t; - -/// MIDI In Jack Descriptor -typedef struct TU_ATTR_PACKED { - uint8_t bLength; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType; ///< Descriptor SubType - uint8_t always_2; /// always 0x2 - uint8_t num_cables_rx; /// rx cable count - uint8_t num_cables_tx; /// tx cable count -} midi_desc_roland_header_t; - -typedef struct -{ - uint8_t dev_addr; - uint8_t itf_num; - - uint8_t ep_in; // IN endpoint address - uint8_t ep_out; // OUT endpoint address - uint16_t ep_in_max; // min( CFG_TUH_MIDI_RX_BUFSIZE, wMaxPacketSize of the IN endpoint) - uint16_t ep_out_max; // min( CFG_TUH_MIDI_TX_BUFSIZE, wMaxPacketSize of the OUT endpoint) - - uint8_t num_cables_rx; // IN endpoint CS descriptor bNumEmbMIDIJack value - uint8_t num_cables_tx; // OUT endpoint CS descriptor bNumEmbMIDIJack value - - // For Stream read()/write() API - // Messages are always 4 bytes long, queue them for reading and writing so the - // callers can use the Stream interface with single-byte read/write calls. - midi_stream_t stream_write; - midi_stream_t stream_read; - - /*------------- From this point, data is not cleared by bus reset -------------*/ - // Endpoint FIFOs - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; - - uint8_t rx_ff_buf[CFG_TUH_MIDI_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE]; - -#if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; -#endif - - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUH_MIDI_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUH_MIDI_EP_BUFSIZE]; - - bool configured; - -#if CFG_MIDI_HOST_DEVSTRINGS -#define MAX_STRING_INDICES 32 - uint8_t all_string_indices[MAX_STRING_INDICES]; - uint8_t num_string_indices; -#define MAX_IN_JACKS 8 -#define MAX_OUT_JACKS 8 - struct { - uint8_t jack_id; - uint8_t jack_type; - uint8_t string_index; - } in_jack_info[MAX_IN_JACKS]; - uint8_t next_in_jack; - struct { - uint8_t jack_id; - uint8_t jack_type; - uint8_t num_source_ids; - uint8_t source_ids[MAX_IN_JACKS / 4]; - uint8_t string_index; - } out_jack_info[MAX_OUT_JACKS]; - uint8_t next_out_jack; - uint8_t ep_in_associated_jacks[MAX_OUT_JACKS / 2]; - uint8_t ep_out_associated_jacks[MAX_IN_JACKS / 2]; -#endif -} midih_interface_t; - -static midih_interface_t _midi_host[CFG_TUH_DEVICE_MAX]; - -static midih_interface_t *get_midi_host(uint8_t dev_addr) { - TU_VERIFY(dev_addr > 0 && dev_addr <= CFG_TUH_DEVICE_MAX); - return (_midi_host + dev_addr - 1); -} - -//------------- Internal prototypes -------------// -static uint32_t write_flush(uint8_t dev_addr, midih_interface_t *midi); - -//--------------------------------------------------------------------+ -// USBH API -//--------------------------------------------------------------------+ -bool midih_init(void) { - tu_memclr(&_midi_host, sizeof(_midi_host)); - // config fifos - for (int inst = 0; inst < CFG_TUH_DEVICE_MAX; inst++) { - midih_interface_t *p_midi_host = &_midi_host[inst]; - tu_fifo_config(&p_midi_host->rx_ff, p_midi_host->rx_ff_buf, CFG_TUH_MIDI_RX_BUFSIZE, 1, false); // true, true - tu_fifo_config(&p_midi_host->tx_ff, p_midi_host->tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, 1, false); // OBVS. - -#if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&p_midi_host->rx_ff, NULL, osal_mutex_create(&p_midi_host->rx_ff_mutex)); - tu_fifo_config_mutex(&p_midi_host->tx_ff, osal_mutex_create(&p_midi_host->tx_ff_mutex), NULL); -#endif - } - return true; -} - -bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - (void)result; - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - if (ep_addr == p_midi_host->ep_in) { - if (0 == xferred_bytes) { - return true; // No data to handle - } - - // receive new data if available - uint32_t packets_queued = 0; - if (xferred_bytes) { - // put in the RX FIFO only non-zero MIDI IN 4-byte packets - uint8_t *buf = p_midi_host->epin_buf; - uint32_t npackets = xferred_bytes / 4; - uint32_t packet_num; - for (packet_num = 0; packet_num < npackets; packet_num++) { - // some devices send back all zero packets even if there is no data ready - uint32_t packet = (uint32_t)((*buf) << 24) | ((uint32_t)(*(buf + 1)) << 16) | ((uint32_t)(*(buf + 2)) << 8) | ((uint32_t)(*(buf + 3))); - if (packet != 0) { - tu_fifo_write_n(&p_midi_host->rx_ff, buf, 4); - ++packets_queued; - TU_LOG3("MIDI RX=%08x\r\n", packet); - } - buf += 4; - } - } - // invoke receive callback if available - if (tuh_midi_rx_cb) { - tuh_midi_rx_cb(dev_addr, packets_queued); - } - } else if (ep_addr == p_midi_host->ep_out) { - if (0 == write_flush(dev_addr, p_midi_host)) { - // If there is no data left, a ZLP should be sent if - // xferred_bytes is multiple of EP size and not zero - if (!tu_fifo_count(&p_midi_host->tx_ff) && xferred_bytes && (0 == (xferred_bytes % p_midi_host->ep_out_max))) { - if (usbh_edpt_claim(dev_addr, p_midi_host->ep_out)) { - TU_ASSERT(usbh_edpt_xfer(dev_addr, p_midi_host->ep_out, XFER_RESULT_SUCCESS, 0)); - } - } - } - if (tuh_midi_tx_cb) { - tuh_midi_tx_cb(dev_addr); - } - } - - return true; -} - -void midih_close(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - if (p_midi_host == NULL) - return; - if (tuh_midi_umount_cb) - tuh_midi_umount_cb(dev_addr, 0); - tu_fifo_clear(&p_midi_host->rx_ff); - tu_fifo_clear(&p_midi_host->tx_ff); - p_midi_host->ep_in = 0; - p_midi_host->ep_in_max = 0; - p_midi_host->ep_out = 0; - p_midi_host->ep_out_max = 0; - p_midi_host->itf_num = 0; - p_midi_host->num_cables_rx = 0; - p_midi_host->num_cables_tx = 0; - p_midi_host->dev_addr = 255; // invalid - p_midi_host->configured = false; - tu_memclr(&p_midi_host->stream_read, sizeof(p_midi_host->stream_read)); - tu_memclr(&p_midi_host->stream_write, sizeof(p_midi_host->stream_write)); -} - -//--------------------------------------------------------------------+ -// Enumeration -//--------------------------------------------------------------------+ -bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { - (void)rhport; - - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - - TU_VERIFY(p_midi_host != NULL); -#if CFG_MIDI_HOST_DEVSTRINGS - p_midi_host->num_string_indices = 0; -#endif - // Some roland devices use vendor specific and have their own header - TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass || TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass); - // There can be just a MIDI interface or an audio and a MIDI interface. Only open the MIDI interface - uint8_t const *p_desc = (uint8_t const *)desc_itf; - uint16_t len_parsed = 0; - if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) { -#if CFG_MIDI_HOST_DEVSTRINGS - // Keep track of any string descriptor that might be here - if (desc_itf->iInterface != 0) - p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface; -#endif - // This driver does not support audio streaming. However, if this is the audio control interface - // there might be a MIDI interface following it. Search through every descriptor until a MIDI - // interface is found or the end of the descriptor is found - while (len_parsed < max_len && (desc_itf->bInterfaceClass != TUSB_CLASS_AUDIO || desc_itf->bInterfaceSubClass != AUDIO_SUBCLASS_MIDI_STREAMING)) { - len_parsed += desc_itf->bLength; - p_desc = tu_desc_next(p_desc); - desc_itf = (tusb_desc_interface_t const *)p_desc; - } - - TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); - } - TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass); - len_parsed += desc_itf->bLength; -#if CFG_MIDI_HOST_DEVSTRINGS - // Keep track of any string descriptor that might be here - if (desc_itf->iInterface != 0) - p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface; -#endif - p_desc = tu_desc_next(p_desc); - TU_LOG1("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); - // Find out if getting the MIDI class specific interface header or an endpoint descriptor - // or a class-specific endpoint descriptor - // Jack descriptors or element descriptors must follow the cs interface header, - // but this driver does not support devices that contain element descriptors - - // assume it is an interface header - midi_desc_header_t const *p_mdh = (midi_desc_header_t const *)p_desc; - TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE && p_mdh->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) || - (p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE && p_mdh->bDescriptorSubType == MIDI_CS_ROLAND_HEADER) || - (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || - p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); - - uint8_t prev_ep_addr = 0; // the CS endpoint descriptor is associated with the previous endpoint descrptor - p_midi_host->itf_num = desc_itf->bInterfaceNumber; - tusb_desc_endpoint_t const *in_desc = NULL; - tusb_desc_endpoint_t const *out_desc = NULL; - while (len_parsed < max_len) { - TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) || - (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || - p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); - - if (p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) { - // The USB host doesn't really need this information unless it uses - // the string descriptor for a jack or Element - - // assume it is an input jack - midi_desc_in_jack_t const *p_mdij = (midi_desc_in_jack_t const *)p_desc; - if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) { - TU_LOG2("Found MIDI Interface Header\r\n"); - } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_IN_JACK) { - // Then it is an in jack. - TU_LOG2("Found in jack\r\n"); -#if CFG_MIDI_HOST_DEVSTRINGS - if (p_midi_host->next_in_jack < MAX_IN_JACKS) { - p_midi_host->in_jack_info[p_midi_host->next_in_jack].jack_id = p_mdij->bJackID; - p_midi_host->in_jack_info[p_midi_host->next_in_jack].jack_type = p_mdij->bJackType; - p_midi_host->in_jack_info[p_midi_host->next_in_jack].string_index = p_mdij->iJack; - ++p_midi_host->next_in_jack; - // Keep track of any string descriptor that might be here - if (p_mdij->iJack != 0) - p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = p_mdij->iJack; - } -#endif - } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_OUT_JACK) { - // then it is an out jack - TU_LOG2("Found out jack\r\n"); -#if CFG_MIDI_HOST_DEVSTRINGS - if (p_midi_host->next_out_jack < MAX_OUT_JACKS) { - midi_desc_out_jack_t const *p_mdoj = (midi_desc_out_jack_t const *)p_desc; - p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_id = p_mdoj->bJackID; - p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_type = p_mdoj->bJackType; - p_midi_host->out_jack_info[p_midi_host->next_out_jack].num_source_ids = p_mdoj->bNrInputPins; - const struct associated_jack_s { - uint8_t id; - uint8_t pin; - } *associated_jack = (const struct associated_jack_s *)(p_desc + 6); - int jack; - for (jack = 0; jack < p_mdoj->bNrInputPins; jack++) { - p_midi_host->out_jack_info[p_midi_host->next_out_jack].source_ids[jack] = associated_jack->id; - } - p_midi_host->out_jack_info[p_midi_host->next_out_jack].string_index = *(p_desc + 6 + p_mdoj->bNrInputPins * 2); - ++p_midi_host->next_out_jack; - if (p_mdoj->iJack != 0) - p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = p_mdoj->iJack; - } -#endif - } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_ELEMENT) { - // the it is an element; -#if CFG_MIDI_HOST_DEVSTRINGS - TU_LOG1("Found element; strings not supported\r\n"); -#else - TU_LOG2("Found element\r\n"); -#endif - } else if (p_mdij->bDescriptorSubType == MIDI_CS_ROLAND_HEADER) { - midi_desc_roland_header_t const *p_rl = (midi_desc_roland_header_t const *)p_desc; - TU_LOG2("Found Roland Header %02x %02x %02x %02x\r\n", p_rl->bLength, p_rl->always_2, p_rl->num_cables_rx, p_rl->num_cables_tx); - if (p_rl->bLength >= sizeof(midi_desc_roland_header_t) && p_rl->always_2 == 0x02) { - TU_VERIFY(p_rl->num_cables_rx < 0x10 && p_rl->num_cables_tx < 0x10); - TU_LOG2("Found Roland Header\r\n"); - p_midi_host->num_cables_rx = (1 << p_rl->num_cables_rx) - 1; - p_midi_host->num_cables_tx = (1 << p_rl->num_cables_tx) - 1; - - } else { - TU_LOG2("Unknown CS Interface sub-type %u\r\n", p_mdij->bDescriptorSubType); - TU_VERIFY(false); // unknown CS Interface sub-type - } - len_parsed += p_mdij->bLength; - } else { - TU_LOG2("Unknown CS Interface sub-type %u\r\n", p_mdij->bDescriptorSubType); - TU_VERIFY(false); // unknown CS Interface sub-type - } - len_parsed += p_mdij->bLength; - } else if (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT) { - TU_LOG2("found CS_ENDPOINT Descriptor for %u\r\n", prev_ep_addr); - TU_VERIFY(prev_ep_addr != 0); - // parse out the mapping between the device's embedded jacks and the endpoints - // Each embedded IN jack is assocated with an OUT endpoint - midi_cs_desc_endpoint_t const *p_csep = (midi_cs_desc_endpoint_t const *)p_mdh; - if (tu_edpt_dir(prev_ep_addr) == TUSB_DIR_OUT) { - TU_VERIFY(p_midi_host->ep_out == prev_ep_addr); - TU_VERIFY(p_midi_host->num_cables_tx == 0); - p_midi_host->num_cables_tx = p_csep->bNumEmbMIDIJack; -#if CFG_MIDI_HOST_DEVSTRINGS - uint8_t jack; - uint8_t max_jack = p_midi_host->num_cables_tx; - if (max_jack > sizeof(p_midi_host->ep_out_associated_jacks)) { - max_jack = sizeof(p_midi_host->ep_out_associated_jacks); - } - for (jack = 0; jack < max_jack; jack++) { - p_midi_host->ep_out_associated_jacks[jack] = p_csep->baAssocJackID[jack]; - } -#endif - } else { - TU_VERIFY(p_midi_host->ep_in == prev_ep_addr); - TU_VERIFY(p_midi_host->num_cables_rx == 0); - p_midi_host->num_cables_rx = p_csep->bNumEmbMIDIJack; -#if CFG_MIDI_HOST_DEVSTRINGS - uint8_t jack; - uint8_t max_jack = p_midi_host->num_cables_rx; - if (max_jack > sizeof(p_midi_host->ep_in_associated_jacks)) { - max_jack = sizeof(p_midi_host->ep_in_associated_jacks); - } - for (jack = 0; jack < max_jack; jack++) { - p_midi_host->ep_in_associated_jacks[jack] = p_csep->baAssocJackID[jack]; - } -#endif - } - len_parsed += p_csep->bLength; - prev_ep_addr = 0; - } else if (p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT) { - // parse out the bulk endpoint info - tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *)p_mdh; - TU_LOG2("found ENDPOINT Descriptor for %u\r\n", p_ep->bEndpointAddress); - if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { - TU_VERIFY(p_midi_host->ep_out == 0); - TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass || p_midi_host->num_cables_tx == 0); - p_midi_host->ep_out = p_ep->bEndpointAddress; - p_midi_host->ep_out_max = p_ep->wMaxPacketSize; - if (p_midi_host->ep_out_max > CFG_TUH_MIDI_TX_BUFSIZE) - p_midi_host->ep_out_max = CFG_TUH_MIDI_TX_BUFSIZE; - prev_ep_addr = p_midi_host->ep_out; - out_desc = p_ep; - } else { - TU_VERIFY(p_midi_host->ep_in == 0); - TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass || p_midi_host->num_cables_rx == 0); - p_midi_host->ep_in = p_ep->bEndpointAddress; - p_midi_host->ep_in_max = p_ep->wMaxPacketSize; - if (p_midi_host->ep_in_max > CFG_TUH_MIDI_RX_BUFSIZE) - p_midi_host->ep_in_max = CFG_TUH_MIDI_RX_BUFSIZE; - prev_ep_addr = p_midi_host->ep_in; - in_desc = p_ep; - } - len_parsed += p_mdh->bLength; - } - if (TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass && (p_midi_host->ep_out != 0 && p_midi_host->num_cables_tx != 0) && (p_midi_host->ep_in != 0 && p_midi_host->num_cables_rx != 0)) { - break; - } - p_desc = tu_desc_next(p_desc); - p_mdh = (midi_desc_header_t const *)p_desc; - } - TU_VERIFY((p_midi_host->ep_out != 0 && p_midi_host->num_cables_tx != 0) || - (p_midi_host->ep_in != 0 && p_midi_host->num_cables_rx != 0)); - TU_LOG1("MIDI descriptor parsed successfully\r\n"); - -#if CFG_MIDI_HOST_DEVSTRINGS - // remove duplicate string indices - for (int idx = 0; idx < p_midi_host->num_string_indices; idx++) { - for (int jdx = idx + 1; jdx < p_midi_host->num_string_indices; jdx++) { - while (jdx < p_midi_host->num_string_indices && p_midi_host->all_string_indices[idx] == p_midi_host->all_string_indices[jdx]) { - // delete the duplicate by overwriting it with the last entry and reducing the number of entries by 1 - p_midi_host->all_string_indices[jdx] = p_midi_host->all_string_indices[p_midi_host->num_string_indices - 1]; - --p_midi_host->num_string_indices; - } - } - } -#endif - if (in_desc) { - TU_ASSERT(tuh_edpt_open(dev_addr, in_desc)); - // Some devices always return exactly the request length so transfers won't complete - // unless you assume every transfer is the last one. - // TODO usbh_edpt_force_last_buffer(dev_addr, p_midi_host->ep_in, true); - } - if (out_desc) { - TU_ASSERT(tuh_edpt_open(dev_addr, out_desc)); - } - p_midi_host->dev_addr = dev_addr; - - if (tuh_midi_mount_cb) { - tuh_midi_mount_cb(dev_addr, p_midi_host->ep_in, p_midi_host->ep_out, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx); - } - return true; -} - -bool tuh_midi_configured(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - return p_midi_host->configured; -} - -bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { - (void)itf_num; - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - p_midi_host->configured = true; - - // TODO I don't think there are any special config things to do for MIDI - usbh_driver_set_config_complete(dev_addr, p_midi_host->itf_num); - return true; -} - -//--------------------------------------------------------------------+ -// Stream API -//--------------------------------------------------------------------+ -static uint32_t write_flush(uint8_t dev_addr, midih_interface_t *midi) { - // No data to send - if (!tu_fifo_count(&midi->tx_ff)) return 0; - - // skip if previous transfer not complete - TU_VERIFY(usbh_edpt_claim(dev_addr, midi->ep_out)); - - uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epout_buf, midi->ep_out_max); - - if (count) { - TU_ASSERT(usbh_edpt_xfer(dev_addr, midi->ep_out, midi->epout_buf, count), 0); - return count; - } else { - // Release endpoint since we don't make any transfer - usbh_edpt_release(dev_addr, midi->ep_out); - return 0; - } -} - -bool tuh_midi_read_poll(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - bool result = false; - - bool in_edpt_not_busy = !usbh_edpt_busy(dev_addr, p_midi_host->ep_in); - if (in_edpt_not_busy) { - TU_LOG2("Requesting poll IN endpoint %d\r\n", p_midi_host->ep_in); - TU_ASSERT(usbh_edpt_xfer(p_midi_host->dev_addr, p_midi_host->ep_in, p_midi_host->epin_buf, p_midi_host->ep_in_max), 0); - result = true; - } else { - // Maybe the IN endpoint is only busy because the RP2040 host hardware - // is retrying a NAK'd IN transfer forever. Try aborting the NAK'd - // transfer to allow other transfers to happen on the one shared - // epx endpoint. - // TODO for RP2040 USB shared endpoint: usbh_edpt_clear_in_on_nak(p_midi_host->dev_addr, p_midi_host->ep_in); - } - return result; -} - -uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - TU_VERIFY(cable_num < p_midi_host->num_cables_tx); - midi_stream_t *stream = &p_midi_host->stream_write; - - uint32_t i = 0; - while ((i < bufsize) && (tu_fifo_remaining(&p_midi_host->tx_ff) >= 4)) { - uint8_t const data = buffer[i]; - i++; - if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) { - // real-time messages need to be sent right away - midi_stream_t streamrt; - streamrt.buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; - streamrt.buffer[1] = data; - streamrt.index = 2; - streamrt.total = 2; - uint16_t const count = tu_fifo_write_n(&p_midi_host->tx_ff, streamrt.buffer, 4); - // FIFO overflown, since we already check fifo remaining. It is probably race condition - TU_ASSERT(count == 4, i); - } else if (stream->index == 0) { - //------------- New event packet -------------// - - uint8_t const msg = data >> 4; - - stream->index = 2; - stream->buffer[1] = data; - - // Check to see if we're still in a SysEx transmit. - if (stream->buffer[0] == MIDI_CIN_SYSEX_START) { - if (data == MIDI_STATUS_SYSEX_END) { - stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; - stream->total = 2; - } else { - stream->total = 4; - } - } else if ((msg >= 0x8 && msg <= 0xB) || msg == 0xE) { - // Channel Voice Messages - stream->buffer[0] = (uint8_t)((cable_num << 4) | msg); - stream->total = 4; - } else if (msg == 0xC || msg == 0xD) { - // Channel Voice Messages, two-byte variants (Program Change and Channel Pressure) - stream->buffer[0] = (uint8_t)((cable_num << 4) | msg); - stream->total = 3; - } else if (msg == 0xf) { - // System message - if (data == MIDI_STATUS_SYSEX_START) { - stream->buffer[0] = MIDI_CIN_SYSEX_START; - stream->total = 4; - } else if (data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT) { - stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE; - stream->total = 3; - } else if (data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER) { - stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE; - stream->total = 4; - } else { - stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; - stream->total = 2; - } - } else { - // Pack individual bytes if we don't support packing them into words. - stream->buffer[0] = (uint8_t)(cable_num << 4 | 0xf); - stream->buffer[2] = 0; - stream->buffer[3] = 0; - stream->index = 2; - stream->total = 2; - } - } else { - //------------- On-going (buffering) packet -------------// - - TU_ASSERT(stream->index < 4, i); - stream->buffer[stream->index] = data; - stream->index++; - // See if this byte ends a SysEx. - if (stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END) { - stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1); - stream->total = stream->index; - } - } - - // Send out packet - if (stream->index >= 2 && stream->index == stream->total) { - // zeroes unused bytes - for (uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0; - TU_LOG3_MEM(stream->buffer, 4, 2); - - uint16_t const count = tu_fifo_write_n(&p_midi_host->tx_ff, stream->buffer, 4); - - // complete current event packet, reset stream - stream->index = 0; - stream->total = 0; - - // FIFO overflown, since we already check fifo remaining. It is probably race condition - TU_ASSERT(count == 4, i); - } - } - return i; -} - -bool tuh_midi_packet_write(uint8_t dev_addr, uint8_t const packet[4]) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - - if (tu_fifo_remaining(&p_midi_host->tx_ff) < 4) { - return false; - } - - tu_fifo_write_n(&p_midi_host->tx_ff, packet, 4); - - return true; -} - -uint32_t tuh_midi_stream_flush(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - - uint32_t bytes_flushed = 0; - if (!usbh_edpt_busy(p_midi_host->dev_addr, p_midi_host->ep_out)) { - bytes_flushed = write_flush(dev_addr, p_midi_host); - } - return bytes_flushed; -} -//--------------------------------------------------------------------+ -// Helper -//--------------------------------------------------------------------+ -uint8_t tuh_midih_get_num_tx_cables(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - TU_VERIFY(p_midi_host->ep_out != 0); // returns 0 if fails - return p_midi_host->num_cables_tx; -} - -uint8_t tuh_midih_get_num_rx_cables(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - TU_VERIFY(p_midi_host->ep_in != 0); // returns 0 if fails - return p_midi_host->num_cables_rx; -} - -bool tuh_midi_packet_read(uint8_t dev_addr, uint8_t packet[4]) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - TU_VERIFY(tu_fifo_count(&p_midi_host->rx_ff) >= 4); - return tu_fifo_read_n(&p_midi_host->rx_ff, packet, 4) == 4; -} - -uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - uint32_t bytes_buffered = 0; - TU_ASSERT(p_cable_num); - TU_ASSERT(p_buffer); - TU_ASSERT(bufsize); - uint8_t one_byte; - if (!tu_fifo_peek(&p_midi_host->rx_ff, &one_byte)) { - return 0; - } - *p_cable_num = (one_byte >> 4) & 0xf; - uint32_t nread = tu_fifo_read_n(&p_midi_host->rx_ff, p_midi_host->stream_read.buffer, 4); - static uint16_t cable_sysex_in_progress; // bit i is set if received MIDI_STATUS_SYSEX_START but not MIDI_STATUS_SYSEX_END - while (nread == 4 && bytes_buffered < bufsize) { - *p_cable_num = (p_midi_host->stream_read.buffer[0] >> 4) & 0x0f; - uint8_t bytes_to_add_to_stream = 0; - if (*p_cable_num < p_midi_host->num_cables_rx) { - // ignore the CIN field; too many devices out there encode this wrong - uint8_t status = p_midi_host->stream_read.buffer[1]; - uint16_t cable_mask = (uint16_t)(1 << *p_cable_num); - if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) { - if (status == MIDI_STATUS_SYSEX_START) { - cable_sysex_in_progress |= cable_mask; - } - // only add the packet if a sysex message is in progress - if (cable_sysex_in_progress & cable_mask) { - ++bytes_to_add_to_stream; - uint8_t idx; - for (idx = 2; idx < 4; idx++) { - if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL) { - ++bytes_to_add_to_stream; - } else if (p_midi_host->stream_read.buffer[idx] == MIDI_STATUS_SYSEX_END) { - ++bytes_to_add_to_stream; - cable_sysex_in_progress &= (uint16_t)~cable_mask; - idx = 4; // force the loop to exit; I hate break statements in loops - } - } - } - } else if (status < MIDI_STATUS_SYSEX_START) { - // then it is a channel message either three bytes or two - uint8_t fake_cin = (status & 0xf0) >> 4; - switch (fake_cin) { - case MIDI_CIN_NOTE_OFF: - case MIDI_CIN_NOTE_ON: - case MIDI_CIN_POLY_KEYPRESS: - case MIDI_CIN_CONTROL_CHANGE: - case MIDI_CIN_PITCH_BEND_CHANGE: - bytes_to_add_to_stream = 3; - break; - case MIDI_CIN_PROGRAM_CHANGE: - case MIDI_CIN_CHANNEL_PRESSURE: - bytes_to_add_to_stream = 2; - break; - default: - break; // Should not get this - } - cable_sysex_in_progress &= (uint16_t)~cable_mask; - } else if (status < MIDI_STATUS_SYSREAL_TIMING_CLOCK) { - switch (status) { - case MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME: - case MIDI_STATUS_SYSCOM_SONG_SELECT: - bytes_to_add_to_stream = 2; - break; - case MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER: - bytes_to_add_to_stream = 3; - break; - case MIDI_STATUS_SYSCOM_TUNE_REQUEST: - case MIDI_STATUS_SYSEX_END: - bytes_to_add_to_stream = 1; - break; - default: - break; - cable_sysex_in_progress &= (uint16_t)~cable_mask; - } - } else { - // Real-time message: can be inserted into a sysex message, - // so do don't clear cable_sysex_in_progress bit - bytes_to_add_to_stream = 1; - } - } - uint8_t idx; - for (idx = 1; idx <= bytes_to_add_to_stream; idx++) { - *p_buffer++ = p_midi_host->stream_read.buffer[idx]; - } - bytes_buffered += bytes_to_add_to_stream; - nread = 0; - if (tu_fifo_peek(&p_midi_host->rx_ff, &one_byte)) { - uint8_t new_cable = (one_byte >> 4) & 0xf; - if (new_cable == *p_cable_num) { - // still on the same cable. Continue reading the stream - nread = tu_fifo_read_n(&p_midi_host->rx_ff, p_midi_host->stream_read.buffer, 4); - } - } - } - - return bytes_buffered; -} - -uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - uint8_t num_cables = 0; - if (p_midi_host) { - num_cables = p_midi_host->num_cables_rx; - } - return num_cables; -} - -uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - uint8_t num_cables = 0; - if (p_midi_host) { - num_cables = p_midi_host->num_cables_tx; - } - return num_cables; -} - -#if CFG_MIDI_HOST_DEVSTRINGS -static uint8_t find_string_index(midih_interface_t *ptr, uint8_t jack_id) { - uint8_t index = 0; - uint8_t assoc; - for (assoc = 0; index == 0 && assoc < ptr->next_in_jack; assoc++) { - if (jack_id == ptr->in_jack_info[assoc].jack_id) { - index = ptr->in_jack_info[assoc].string_index; - } - } - for (assoc = 0; index == 0 && assoc < ptr->next_out_jack; assoc++) { - if (jack_id == ptr->out_jack_info[assoc].jack_id) { - index = ptr->out_jack_info[assoc].string_index; - } - } - return index; -} -uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t *istrings, uint8_t max_istrings) { - uint8_t nstrings = 0; - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - nstrings = p_midi_host->num_cables_rx; - if (nstrings > max_istrings) { - nstrings = max_istrings; - } - uint8_t jack; - for (jack = 0; jack < nstrings; jack++) { - uint8_t jack_id = p_midi_host->ep_in_associated_jacks[jack]; - istrings[jack] = find_string_index(p_midi_host, jack_id); - } - return nstrings; -} - -uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t *istrings, uint8_t max_istrings) { - uint8_t nstrings = 0; - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - nstrings = p_midi_host->num_cables_tx; - if (nstrings > max_istrings) { - nstrings = max_istrings; - } - uint8_t jack; - for (jack = 0; jack < nstrings; jack++) { - uint8_t jack_id = p_midi_host->ep_out_associated_jacks[jack]; - istrings[jack] = find_string_index(p_midi_host, jack_id); - } - return nstrings; -} - -uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t **istrings) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - TU_VERIFY(p_midi_host != NULL); - uint8_t nstrings = p_midi_host->num_string_indices; - if (nstrings) - *istrings = p_midi_host->all_string_indices; - return nstrings; -} -#endif -#endif - diff --git a/src/pico/midi_host.cpp b/src/pico/midi_host.cpp new file mode 100644 index 000000000..012e0f098 --- /dev/null +++ b/src/pico/midi_host.cpp @@ -0,0 +1,541 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUH_ENABLED && CFG_TUH_MIDI_CUSTOM) + +#include "host/usbh.h" +#include "host/usbh_pvt.h" + +#include "midi_host.h" +#include "shared_main.h" +#include + +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUH_MIDI_CUSTOM_LOG_LEVEL +#define CFG_TUH_MIDI_CUSTOM_LOG_LEVEL 0 +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_MIDI_CUSTOM_LOG_LEVEL, __VA_ARGS__) + +#define MIDI_CS_ROLAND_HEADER 0xF1 +//--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t idx, const tuh_midi_descriptor_cb_t *desc_cb_data) +{ + (void)idx; + (void)desc_cb_data; +} +TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t *mount_cb_data) +{ + (void)idx; + (void)mount_cb_data; +} +TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t idx) { (void)idx; } +TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t idx, uint32_t xferred_bytes) +{ + (void)idx; + (void)xferred_bytes; +} +TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t idx, uint32_t xferred_bytes) +{ + (void)idx; + (void)xferred_bytes; +} + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +typedef struct +{ + uint8_t daddr; + uint8_t bInterfaceNumber; // interface number of MIDI streaming + uint8_t iInterface; + uint8_t itf_count; // number of interfaces including Audio Control + MIDI streaming + + uint8_t rx_cable_count; // IN endpoint CS descriptor bNumEmbMIDIJack value + uint8_t tx_cable_count; // OUT endpoint CS descriptor bNumEmbMIDIJack value + +#if CFG_TUH_MIDI_CUSTOM_STREAM_API + // For Stream read()/write() API + // Messages are always 4 bytes long, queue them for reading and writing so the + // callers can use the Stream interface with single-byte read/write calls. + midi_driver_stream_t stream_write; + midi_driver_stream_t stream_read; +#endif + + bool mounted; +} midih_interface_t; + +typedef struct +{ + TUH_EPBUF_DEF(tx, TUH_EPSIZE_BULK_MAX); + TUH_EPBUF_DEF(rx, TUH_EPSIZE_BULK_MAX); +} midih_epbuf_t; + +/// MIDI In Jack Descriptor +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType; ///< Descriptor SubType + uint8_t always_2; /// always 0x2 + uint8_t num_cables_rx; /// rx cable count + uint8_t num_cables_tx; /// tx cable count +} midi_desc_roland_header_t; +static midih_interface_t _midi_host[CFG_TUH_MIDI_CUSTOM]; +CFG_TUH_MEM_SECTION static midih_epbuf_t _midi_epbuf[CFG_TUH_MIDI_CUSTOM]; + +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline uint8_t find_new_midi_index(void) +{ + for (uint8_t idx = 0; idx < CFG_TUH_MIDI_CUSTOM; idx++) + { + if (_midi_host[idx].daddr == 0) + { + return idx; + } + } + return TUSB_INDEX_INVALID_8; +} + +static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) +{ + for (uint8_t idx = 0; idx < CFG_TUH_MIDI_CUSTOM; idx++) + { + const midih_interface_t *p_midi = &_midi_host[idx]; + if ((p_midi->daddr == daddr) && + (ep_addr == usbMidi.ep_stream.rx.ep_addr || ep_addr == usbMidi.ep_stream.tx.ep_addr)) + { + return idx; + } + } + return TUSB_INDEX_INVALID_8; +} + +//--------------------------------------------------------------------+ +// USBH API +//--------------------------------------------------------------------+ +bool midih_init(void) +{ + tu_memclr(&_midi_host, sizeof(_midi_host)); + return true; +} + +bool midih_deinit(void) +{ + // for (size_t i = 0; i < CFG_TUH_MIDI_CUSTOM; i++) { + // midih_interface_t* p_midi = &_midi_host[i]; + // tu_edpt_stream_deinit(&usbMidi.ep_stream.rx); + // tu_edpt_stream_deinit(&usbMidi.ep_stream.tx); + // } + return true; +} + +void midih_close(uint8_t daddr) +{ + for (uint8_t idx = 0; idx < CFG_TUH_MIDI_CUSTOM; idx++) + { + midih_interface_t *p_midi = &_midi_host[idx]; + if (p_midi->daddr == daddr) + { + TU_LOG_DRV(" MIDI close addr = %u index = %u\r\n", daddr, idx); + tuh_midi_umount_cb(idx); + + p_midi->bInterfaceNumber = 0; + p_midi->rx_cable_count = 0; + p_midi->tx_cable_count = 0; + p_midi->daddr = 0; + p_midi->mounted = false; +#if CFG_TUH_MIDI_CUSTOM_STREAM_API + tu_memclr(&p_midi->stream_read, sizeof(p_midi->stream_read)); + tu_memclr(&p_midi->stream_write, sizeof(p_midi->stream_write)); +#endif + + tu_edpt_stream_close(&usbMidi.ep_stream.rx); + tu_edpt_stream_close(&usbMidi.ep_stream.tx); + } + } +} + +bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void)result; + const uint8_t idx = get_idx_by_ep_addr(dev_addr, ep_addr); + TU_VERIFY(idx < CFG_TUH_MIDI_CUSTOM); + midih_interface_t *p_midi = &_midi_host[idx]; + tu_edpt_stream_t *ep_str_rx = &usbMidi.ep_stream.rx; + tu_edpt_stream_t *ep_str_tx = &usbMidi.ep_stream.tx; + + if (ep_addr == ep_str_rx->ep_addr) + { + // receive new data, put it into FIFO and invoke callback if available + // Note: some devices send back all zero packets even if there is no data ready + if (xferred_bytes && !tu_mem_is_zero(ep_str_rx->ep_buf, xferred_bytes)) + { + tu_edpt_stream_read_xfer_complete(ep_str_rx, xferred_bytes); + tuh_midi_rx_cb(idx, xferred_bytes); + } + + tu_edpt_stream_read_xfer(ep_str_rx); // prepare for next transfer + } + else if (ep_addr == ep_str_tx->ep_addr) + { + tuh_midi_tx_cb(idx, xferred_bytes); + + if (0 == tu_edpt_stream_write_xfer(ep_str_tx)) + { + // If there is no data left, a ZLP should be sent if + // xferred_bytes is multiple of EP size and not zero + tu_edpt_stream_write_zlp_if_needed(ep_str_tx, xferred_bytes); + } + } + + return true; +} + +//--------------------------------------------------------------------+ +// Enumeration +//--------------------------------------------------------------------+ +uint16_t midih_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface_t *desc_itf, uint16_t max_len) +{ + (void)rhport; + // Some roland devices use vendor specific and have their own header + TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass || TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); + bool roland = TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass; + const uint8_t *desc_start = (const uint8_t *)desc_itf; + const uint8_t *p_desc = desc_start; + const uint8_t *desc_end = desc_start + max_len; + + const uint8_t idx = find_new_midi_index(); + TU_VERIFY(idx < CFG_TUH_MIDI_CUSTOM, 0); + midih_interface_t *p_midi = &_midi_host[idx]; + p_midi->itf_count = 0; + + tuh_midi_descriptor_cb_t desc_cb = {0}; + desc_cb.jack_num = 0; + + // There can be just a MIDI or an Audio + MIDI interface + // - If there is Audio Control Interface + Audio Header descriptor, then skip it. + // - If there is an Audio Control Interface + Audio Streaming Interface, then ignore the Audio Streaming Interface. + // Future: + // Note that if this driver is used with an USB Audio Streaming host driver, + // then call that driver first. If the MIDI interface comes before the + // audio streaming interface, then the audio driver will have to call this + // driver after parsing the audio control interface and then resume parsing + // the streaming audio interface. + if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) + { + TU_VERIFY(max_len > 2 * sizeof(tusb_desc_interface_t) + sizeof(midi10_desc_cs_ac_interface_t), 0); + p_desc = tu_desc_next(p_desc); + TU_VERIFY(tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && + tu_desc_subtype(p_desc) == AUDIO10_CS_AC_INTERFACE_HEADER, + 0); + desc_cb.desc_audio_control = desc_itf; + + p_desc = tu_desc_next(p_desc); + desc_itf = (const tusb_desc_interface_t *)p_desc; + p_midi->itf_count = 1; + // skip non-interface and non-midi streaming descriptors + while (tu_desc_in_bounds(p_desc, desc_end) && (desc_itf->bDescriptorType != TUSB_DESC_INTERFACE || + (desc_itf->bInterfaceClass == TUSB_CLASS_AUDIO && + desc_itf->bInterfaceSubClass != AUDIO_SUBCLASS_MIDI_STREAMING))) + { + if (desc_itf->bDescriptorType == TUSB_DESC_INTERFACE && desc_itf->bAlternateSetting == 0) + { + p_midi->itf_count++; + } + p_desc = tu_desc_next(p_desc); + desc_itf = (const tusb_desc_interface_t *)p_desc; + } + TU_VERIFY(p_desc < desc_end, 0); + TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass, 0); + } + TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass, 0); + + TU_LOG_DRV("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); + p_midi->bInterfaceNumber = desc_itf->bInterfaceNumber; + p_midi->iInterface = desc_itf->iInterface; + p_midi->itf_count++; + desc_cb.desc_midi = desc_itf; + + bool found_new_interface = false; + do + { + p_desc = tu_desc_next(p_desc); + if (!tu_desc_in_bounds(p_desc, desc_end)) + { + break; + } + switch (tu_desc_type(p_desc)) + { + case TUSB_DESC_INTERFACE: + found_new_interface = true; + break; + + case TUSB_DESC_CS_INTERFACE: + switch (tu_desc_subtype(p_desc)) + { + case MIDI_CS_INTERFACE_HEADER: + TU_LOG_DRV(" Interface Header descriptor\r\n"); + desc_cb.desc_header = p_desc; + break; + + case MIDI_CS_INTERFACE_IN_JACK: + case MIDI_CS_INTERFACE_OUT_JACK: + { + TU_LOG_DRV(" Jack %s %s descriptor \r\n", + tu_desc_subtype(p_desc) == MIDI_CS_INTERFACE_IN_JACK ? "IN" : "OUT", + p_desc[3] == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); + if (desc_cb.jack_num < TU_ARRAY_SIZE(desc_cb.desc_jack)) + { + desc_cb.desc_jack[desc_cb.jack_num++] = p_desc; + } + break; + } + + case MIDI_CS_INTERFACE_ELEMENT: + TU_LOG_DRV(" Element descriptor\r\n"); + desc_cb.desc_element = p_desc; + break; + + case MIDI_CS_ROLAND_HEADER: + { + midi_desc_roland_header_t const *p_rl = (midi_desc_roland_header_t const *)p_desc; + TU_LOG2("Found Roland Header %02x %02x %02x %02x\r\n", p_rl->bLength, p_rl->always_2, p_rl->num_cables_rx, p_rl->num_cables_tx); + if (p_rl->bLength >= sizeof(midi_desc_roland_header_t) && p_rl->always_2 == 0x02) + { + TU_VERIFY(p_rl->num_cables_rx < 0x10 && p_rl->num_cables_tx < 0x10); + TU_LOG2("Found Roland Header\r\n"); + p_midi->rx_cable_count = (1 << p_rl->num_cables_rx) - 1; + p_midi->tx_cable_count = (1 << p_rl->num_cables_tx) - 1; + break; + } + TU_LOG_DRV(" Unknown CS Interface sub-type %u\r\n", tu_desc_subtype(p_desc)); + break; + } + default: + TU_LOG_DRV(" Unknown CS Interface sub-type %u\r\n", tu_desc_subtype(p_desc)); + break; + } + break; + + case TUSB_DESC_ENDPOINT: + { + const tusb_desc_endpoint_t *p_ep = (const tusb_desc_endpoint_t *)p_desc; + + p_desc = tu_desc_next(p_desc); // next to CS endpoint + TU_VERIFY(tu_desc_in_bounds(p_desc, desc_end), 0); + tu_edpt_stream_t *ep_stream; + if (roland) + { + if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) + { + desc_cb.desc_epout = p_ep; + ep_stream = &usbMidi.ep_stream.tx; + } + else + { + desc_cb.desc_epin = p_ep; + ep_stream = &usbMidi.ep_stream.rx; + } + } + else + { + const midi_desc_cs_endpoint_t *p_csep = (const midi_desc_cs_endpoint_t *)p_desc; + + TU_LOG_DRV(" Endpoint and CS_Endpoint descriptor %02x\r\n", p_ep->bEndpointAddress); + if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) + { + p_midi->tx_cable_count = p_csep->bNumEmbMIDIJack; + desc_cb.desc_epout = p_ep; + ep_stream = &usbMidi.ep_stream.tx; + } + else + { + p_midi->rx_cable_count = p_csep->bNumEmbMIDIJack; + desc_cb.desc_epin = p_ep; + ep_stream = &usbMidi.ep_stream.rx; + } + } + TU_ASSERT(tuh_edpt_open(dev_addr, p_ep), 0); + tu_edpt_stream_open(ep_stream, dev_addr, p_ep, tu_edpt_packet_size(p_ep)); + tu_edpt_stream_clear(ep_stream); + + break; + } + + default: + break; // skip unknown descriptor + } + } while (!found_new_interface); + + desc_cb.desc_midi_total_len = (uint16_t)((uintptr_t)p_desc - (uintptr_t)desc_start); + + p_midi->daddr = dev_addr; + tuh_midi_descriptor_cb(idx, &desc_cb); + + return desc_cb.desc_midi_total_len; +} + +bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + uint8_t idx = tuh_midi_itf_get_index(dev_addr, itf_num); + TU_ASSERT(idx < CFG_TUH_MIDI_CUSTOM); + midih_interface_t *p_midi = &_midi_host[idx]; + p_midi->mounted = true; + + const tuh_midi_mount_cb_t mount_cb_data = { + .daddr = dev_addr, + .bInterfaceNumber = p_midi->bInterfaceNumber, + .rx_cable_count = p_midi->rx_cable_count, + .tx_cable_count = p_midi->tx_cable_count, + }; + tuh_midi_mount_cb(idx, &mount_cb_data); + + tu_edpt_stream_read_xfer(&usbMidi.ep_stream.rx); // prepare for incoming data + + // No special config things to do for MIDI + usbh_driver_set_config_complete(dev_addr, p_midi->bInterfaceNumber); + return true; +} + +//--------------------------------------------------------------------+ +// API +//--------------------------------------------------------------------+ +bool tuh_midi_mounted(uint8_t idx) +{ + TU_VERIFY(idx < CFG_TUH_MIDI_CUSTOM); + midih_interface_t *p_midi = &_midi_host[idx]; + return p_midi->mounted; +} + +uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num) +{ + for (uint8_t idx = 0; idx < CFG_TUH_MIDI_CUSTOM; idx++) + { + const midih_interface_t *p_midi = &_midi_host[idx]; + if (p_midi->daddr == daddr && + (p_midi->bInterfaceNumber == itf_num || + p_midi->bInterfaceNumber == (uint8_t)(itf_num + p_midi->itf_count - 1))) + { + return idx; + } + } + return TUSB_INDEX_INVALID_8; +} + +bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t *info) +{ + midih_interface_t *p_midi = &_midi_host[idx]; + TU_VERIFY(p_midi && info); + + info->daddr = p_midi->daddr; + + // re-construct descriptor + tusb_desc_interface_t *desc = &info->desc; + desc->bLength = sizeof(tusb_desc_interface_t); + desc->bDescriptorType = TUSB_DESC_INTERFACE; + + desc->bInterfaceNumber = p_midi->bInterfaceNumber; + desc->bAlternateSetting = 0; + desc->bNumEndpoints = 0; + if (tu_edpt_stream_is_opened(&usbMidi.ep_stream.tx)) + { + desc->bNumEndpoints++; + } + if (tu_edpt_stream_is_opened(&usbMidi.ep_stream.rx)) + { + desc->bNumEndpoints++; + } + desc->bInterfaceClass = TUSB_CLASS_AUDIO; + desc->bInterfaceSubClass = AUDIO_SUBCLASS_MIDI_STREAMING; + desc->bInterfaceProtocol = 0; + desc->iInterface = p_midi->iInterface; + + return true; +} + +uint8_t tuh_midi_get_tx_cable_count(uint8_t idx) +{ + TU_VERIFY(idx < CFG_TUH_MIDI_CUSTOM); + midih_interface_t *p_midi = &_midi_host[idx]; + TU_VERIFY(usbMidi.ep_stream.tx.ep_addr != 0, 0); + return p_midi->tx_cable_count; +} + +uint8_t tuh_midi_get_rx_cable_count(uint8_t idx) +{ + TU_VERIFY(idx < CFG_TUH_MIDI_CUSTOM); + midih_interface_t *p_midi = &_midi_host[idx]; + TU_VERIFY(usbMidi.ep_stream.rx.ep_addr != 0, 0); + return p_midi->rx_cable_count; +} + +uint32_t tuh_midi_read_available(uint8_t idx) +{ + TU_VERIFY(idx < CFG_TUH_MIDI_CUSTOM); + midih_interface_t *p_midi = &_midi_host[idx]; + return tu_edpt_stream_read_available(&usbMidi.ep_stream.rx); +} + +uint32_t tuh_midi_write_flush(uint8_t idx) +{ + TU_VERIFY(idx < CFG_TUH_MIDI_CUSTOM); + midih_interface_t *p_midi = &_midi_host[idx]; + return tu_edpt_stream_write_xfer(&usbMidi.ep_stream.tx); +} + +//--------------------------------------------------------------------+ +// Packet API +//--------------------------------------------------------------------+ +uint32_t tuh_midi_packet_read_n(uint8_t idx, uint8_t *buffer, uint32_t bufsize) +{ + TU_VERIFY(idx < CFG_TUH_MIDI_CUSTOM && buffer && bufsize > 0, 0); + midih_interface_t *p_midi = &_midi_host[idx]; + + uint32_t count4 = tu_min32(bufsize, tu_edpt_stream_read_available(&usbMidi.ep_stream.rx)); + count4 = tu_align4(count4); // round down to multiple of 4 + TU_VERIFY(count4 > 0, 0); + return tu_edpt_stream_read(&usbMidi.ep_stream.rx, buffer, count4); +} + +uint32_t tuh_midi_packet_write_n(uint8_t idx, const uint8_t *buffer, uint32_t bufsize) +{ + TU_VERIFY(idx < CFG_TUH_MIDI_CUSTOM && buffer && bufsize > 0, 0); + midih_interface_t *p_midi = &_midi_host[idx]; + + const uint32_t bufsize4 = tu_align4(bufsize); + TU_VERIFY(bufsize4 > 0, 0); + return tu_edpt_stream_write(&usbMidi.ep_stream.tx, buffer, bufsize4); +} + +#endif \ No newline at end of file diff --git a/src/pico/midi_host.h b/src/pico/midi_host.h index b5eac9591..9694f367e 100644 --- a/src/pico/midi_host.h +++ b/src/pico/midi_host.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -24,77 +24,124 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_MIDI_HOST_H_ -#define _TUSB_MIDI_HOST_H_ +#ifndef TUSB_MIDI_HOST_H_ +#define TUSB_MIDI_HOST_H_ #include "class/audio/audio.h" - #include "class/midi/midi.h" #ifdef __cplusplus - extern "C" { +extern "C" { #endif //--------------------------------------------------------------------+ // Class Driver Configuration //--------------------------------------------------------------------+ +#ifndef CFG_TUH_MIDI_RX_BUFSIZE + #define CFG_TUH_MIDI_RX_BUFSIZE TUH_EPSIZE_BULK_MAX +#endif -// TODO Highspeed bulk transfer can be up to 512 bytes -#ifndef CFG_TUH_HID_EPIN_BUFSIZE -#define CFG_TUH_HID_EPIN_BUFSIZE 64 +#ifndef CFG_TUH_MIDI_TX_BUFSIZE + #define CFG_TUH_MIDI_TX_BUFSIZE TUH_EPSIZE_BULK_MAX #endif -#ifndef CFG_TUH_HID_EPOUT_BUFSIZE -#define CFG_TUH_HID_EPOUT_BUFSIZE 64 +#ifndef CFG_TUH_MIDI_EP_BUFSIZE + #define CFG_TUH_MIDI_EP_BUFSIZE TUH_EPSIZE_BULK_MAX #endif -typedef struct -{ - uint8_t bLength ; ///< Size of this descriptor in bytes (4+bNumEmbMIDIJack) - uint8_t bDescriptorType ; ///< Descriptor Type, must be CS_ENDPOINT - uint8_t bDescriptorSubType ; ///< Descriptor SubType, must be MS_GENERAL - uint8_t bNumEmbMIDIJack; ; ///< Number of embedded MIDI jacks associated with this endpoint - uint8_t baAssocJackID[]; ; ///< A list of associated jacks -} midi_cs_desc_endpoint_t; -enum -{ - MIDI_MAX_DATA_VAL = 0x7F, -}; +// Enable the MIDI stream read/write API. Some library can work with raw USB MIDI packet +// Disable this can save driver footprint. +#ifndef CFG_TUH_MIDI_STREAM_API + #define CFG_TUH_MIDI_STREAM_API 1 +#endif //--------------------------------------------------------------------+ -// Application API (Single Interface) +// Application Types //--------------------------------------------------------------------+ -bool tuh_midi_configured (uint8_t dev_addr); +typedef struct { + const tusb_desc_interface_t *desc_audio_control; + const tusb_desc_interface_t *desc_midi; // start of whole midi interface descriptor + uint16_t desc_midi_total_len; + + const uint8_t *desc_header; + const uint8_t *desc_element; + const tusb_desc_endpoint_t *desc_epin; // endpoint IN descriptor, CS_ENDPOINT is right after + const tusb_desc_endpoint_t *desc_epout; // endpoint OUT descriptor, CS_ENDPOINT is right after + + uint8_t jack_num; + const uint8_t *desc_jack[32]; // list of jack descriptors (embedded + external) +} tuh_midi_descriptor_cb_t; + +typedef struct { + uint8_t daddr; + uint8_t bInterfaceNumber; // interface number of MIDI streaming + uint8_t rx_cable_count; + uint8_t tx_cable_count; +} tuh_midi_mount_cb_t; -// return the number of virtual midi cables on the device's OUT endpoint -uint8_t tuh_midih_get_num_tx_cables (uint8_t dev_addr); +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Check if MIDI interface is mounted +bool tuh_midi_mounted(uint8_t idx); + +// Get Interface index from device address + interface number +// return TUSB_INDEX_INVALID_8 (0xFF) if not found +uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num); + +// Get Interface information +// return true if index is correct and interface is currently mounted +bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t *info); // return the number of virtual midi cables on the device's IN endpoint -uint8_t tuh_midih_get_num_rx_cables (uint8_t dev_addr); - -// request available data from the device. tuh_midi_message_received_cb() will -// be called if the device has any data to send. Otherwise, the device will -// respond NAK. This function blocks until the transfer completes or the -// devices sends NAK. -// This function will return false if the hardware is busy. -bool tuh_midi_read_poll( uint8_t dev_addr ); - -// Queue a packet to the device. The application -// must call tuh_midi_stream_flush to actually have the -// data go out. It is up to the application to properly -// format this packet; this function does not check. -// Returns true if the packet was successfully queued. -bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]); +uint8_t tuh_midi_get_rx_cable_count(uint8_t idx); -// Queue a message to the device. The application -// must call tuh_midi_stream_flush to actually have the -// data go out. -uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t const* p_buffer, uint32_t bufsize); +// return the number of virtual midi cables on the device's OUT endpoint +uint8_t tuh_midi_get_tx_cable_count(uint8_t idx); + +// return the raw number of bytes available. +// Note: this is related but not the same as number of stream bytes available. +uint32_t tuh_midi_read_available(uint8_t idx); // Send any queued packets to the device if the host hardware is able to do it // Returns the number of bytes flushed to the host hardware or 0 if // the host hardware is busy or there is nothing in queue to send. -uint32_t tuh_midi_stream_flush( uint8_t dev_addr); +uint32_t tuh_midi_write_flush(uint8_t idx); + +//--------------------------------------------------------------------+ +// Packet API +//--------------------------------------------------------------------+ + +// Read all available MIDI packets from the connected device +// Return number of bytes read (always multiple of 4) +uint32_t tuh_midi_packet_read_n(uint8_t idx, uint8_t *buffer, uint32_t bufsize); + +// Read a raw MIDI packet from the connected device +// Return true if a packet was returned +TU_ATTR_ALWAYS_INLINE static inline bool tuh_midi_packet_read(uint8_t idx, uint8_t packet[4]) { + return 4 == tuh_midi_packet_read_n(idx, packet, 4); +} + +// Write all 4-byte packets, data is locally buffered and only transferred when buffered bytes +// reach the endpoint packet size or tuh_midi_write_flush() is called +uint32_t tuh_midi_packet_write_n(uint8_t idx, const uint8_t *buffer, uint32_t bufsize); + +// Write a 4-bytes packet to the device. +// Returns true if the packet was successfully queued. +TU_ATTR_ALWAYS_INLINE static inline bool tuh_midi_packet_write(uint8_t idx, const uint8_t packet[4]) { + return 4 == tuh_midi_packet_write_n(idx, packet, 4); +} + +//--------------------------------------------------------------------+ +// Stream API +//--------------------------------------------------------------------+ +#if CFG_TUH_MIDI_STREAM_API + +// Queue a message to the device using stream API. data is locally buffered and only transferred when buffered bytes +// reach the endpoint packet size or tuh_midi_write_flush() is called +// Returns number of bytes was successfully queued. +uint32_t tuh_midi_stream_write(uint8_t idx, uint8_t cable_num, const uint8_t *p_buffer, uint32_t bufsize); // Get the MIDI stream from the device. Set the value pointed // to by p_cable_num to the MIDI cable number intended to receive it. @@ -103,47 +150,42 @@ uint32_t tuh_midi_stream_flush( uint8_t dev_addr); // Note that this function ignores the CIN field of the MIDI packet // because a number of commercial devices out there do not encode // it properly. -uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize); +uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize); -// Read a raw MIDI packet from the connected device -// This function does not parse the packet format -// Return true if a packet was returned -bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]); - -uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr); -uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr); -#if CFG_MIDI_HOST_DEVSTRINGS -uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); -uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); -uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings); #endif -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -bool midih_init (void); -bool midih_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); -bool midih_set_config (uint8_t dev_addr, uint8_t itf_num); -bool midih_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -void midih_close (uint8_t dev_addr); //--------------------------------------------------------------------+ // Callbacks (Weak is optional) //--------------------------------------------------------------------+ +// Invoked when MIDI interface is detected in enumeration. Application can copy/parse descriptor if needed. +// Note: may be fired before tuh_midi_mount_cb(), therefore midi interface is not mounted/ready. +void tuh_midi_descriptor_cb(uint8_t idx, const tuh_midi_descriptor_cb_t *desc_cb_data); + // Invoked when device with MIDI interface is mounted. -// If the MIDI host application requires MIDI IN, it should requst an -// IN transfer here. The device will likely NAK this transfer. How the driver -// handles the NAK is hardware dependent. -TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t in_ep, uint8_t out_ep, uint8_t num_cables_rx, uint16_t num_cables_tx); +void tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t *mount_cb_data); // Invoked when device with MIDI interface is un-mounted -// For now, the instance parameter is always 0 and can be ignored -TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t dev_addr, uint8_t instance); +void tuh_midi_umount_cb(uint8_t idx); + +// Invoked when received new data +void tuh_midi_rx_cb(uint8_t idx, uint32_t xferred_bytes); + +// Invoked when a TX is complete and therefore space becomes available in TX buffer +void tuh_midi_tx_cb(uint8_t idx, uint32_t xferred_bytes); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +bool midih_init(void); +bool midih_deinit(void); +uint16_t midih_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface_t *desc_itf, uint16_t max_len); +bool midih_set_config(uint8_t dev_addr, uint8_t itf_num); +bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +void midih_close(uint8_t daddr); -TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets); -TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t dev_addr); #ifdef __cplusplus } #endif -#endif /* _TUSB_MIDI_HOST_H_ */ +#endif \ No newline at end of file diff --git a/src/pico/pins.cpp b/src/pico/pins.cpp index c2a0b747c..fad294134 100644 --- a/src/pico/pins.cpp +++ b/src/pico/pins.cpp @@ -102,4 +102,11 @@ uint16_t multiplexer_read(uint8_t pin, uint32_t mask, uint32_t bits) { return adc_read() << 4; } return 0; +} +uint8_t matrix_read(uint8_t pin, uint8_t outPin) { + gpio_put(outPin, 0); + sleep_us(1); + uint8_t ret = gpio_get(pin); + gpio_put(outPin, 1); + return ret; } \ No newline at end of file diff --git a/src/pico/quadrature_encoder.c b/src/pico/quadrature_encoder.c new file mode 100644 index 000000000..0855eb9b2 --- /dev/null +++ b/src/pico/quadrature_encoder.c @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/stdlib.h" +#include "hardware/pio.h" +#include "hardware/timer.h" + +#include "quadrature_encoder.pio.h" + +// +// ---- quadrature encoder interface example +// +// the PIO program reads phase A/B of a quadrature encoder and increments or +// decrements an internal counter to keep the current absolute step count +// updated. At any point, the main code can query the current count by using +// the quadrature_encoder_*_count functions. The counter is kept in a full +// 32 bit register that just wraps around. Two's complement arithmetic means +// that it can be interpreted as a 32-bit signed or unsigned value, and it will +// work anyway. +// +// As an example, a two wheel robot being controlled at 100Hz, can use two +// state machines to read the two encoders and in the main control loop it can +// simply ask for the current encoder counts to get the absolute step count. It +// can also subtract the values from the last sample to check how many steps +// each wheel as done since the last sample period. +// +// One advantage of this approach is that it requires zero CPU time to keep the +// encoder count updated and because of that it supports very high step rates. +// + +// int main() { +// int new_value, delta, old_value = 0; +// int last_value = -1, last_delta = -1; + +// // Base pin to connect the A phase of the encoder. +// // The B phase must be connected to the next pin +// const uint PIN_AB = 10; + +// stdio_init_all(); +// printf("Hello from quadrature encoder\n"); + +// PIO pio = pio0; +// const uint sm = 0; + +// // we don't really need to keep the offset, as this program must be loaded +// // at offset 0 +// pio_add_program(pio, &quadrature_encoder_program); +// quadrature_encoder_program_init(pio, sm, PIN_AB, 0); + +// while (1) { +// // note: thanks to two's complement arithmetic delta will always +// // be correct even when new_value wraps around MAXINT / MININT +// new_value = quadrature_encoder_get_count(pio, sm); +// delta = new_value - old_value; +// old_value = new_value; + +// if (new_value != last_value || delta != last_delta ) { +// printf("position %8d, delta %6d\n", new_value, delta); +// last_value = new_value; +// last_delta = delta; +// } +// sleep_ms(100); +// } +// } \ No newline at end of file diff --git a/src/pico/quadrature_encoder.pio b/src/pico/quadrature_encoder.pio new file mode 100644 index 000000000..43fe58e62 --- /dev/null +++ b/src/pico/quadrature_encoder.pio @@ -0,0 +1,145 @@ +; +; Copyright (c) 2023 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; +.pio_version 0 // only requires PIO version 0 + +.program quadrature_encoder + +; the code must be loaded at address 0, because it uses computed jumps +.origin 0 + + +; the code works by running a loop that continuously shifts the 2 phase pins into +; ISR and looks at the lower 4 bits to do a computed jump to an instruction that +; does the proper "do nothing" | "increment" | "decrement" action for that pin +; state change (or no change) + +; ISR holds the last state of the 2 pins during most of the code. The Y register +; keeps the current encoder count and is incremented / decremented according to +; the steps sampled + +; the program keeps trying to write the current count to the RX FIFO without +; blocking. To read the current count, the user code must drain the FIFO first +; and wait for a fresh sample (takes ~4 SM cycles on average). The worst case +; sampling loop takes 10 cycles, so this program is able to read step rates up +; to sysclk / 10 (e.g., sysclk 125MHz, max step rate = 12.5 Msteps/sec) + +; 00 state + JMP update ; read 00 + JMP decrement ; read 01 + JMP increment ; read 10 + JMP update ; read 11 + +; 01 state + JMP increment ; read 00 + JMP update ; read 01 + JMP update ; read 10 + JMP decrement ; read 11 + +; 10 state + JMP decrement ; read 00 + JMP update ; read 01 + JMP update ; read 10 + JMP increment ; read 11 + +; to reduce code size, the last 2 states are implemented in place and become the +; target for the other jumps + +; 11 state + JMP update ; read 00 + JMP increment ; read 01 +decrement: + ; note: the target of this instruction must be the next address, so that + ; the effect of the instruction does not depend on the value of Y. The + ; same is true for the "JMP X--" below. Basically "JMP Y--, " + ; is just a pure "decrement Y" instruction, with no other side effects + JMP Y--, update ; read 10 + + ; this is where the main loop starts +.wrap_target +update: + MOV ISR, Y ; read 11 + PUSH noblock + +sample_pins: + ; we shift into ISR the last state of the 2 input pins (now in OSR) and + ; the new state of the 2 pins, thus producing the 4 bit target for the + ; computed jump into the correct action for this state. Both the PUSH + ; above and the OUT below zero out the other bits in ISR + OUT ISR, 2 + IN PINS, 2 + + ; save the state in the OSR, so that we can use ISR for other purposes + MOV OSR, ISR + ; jump to the correct state machine action + MOV PC, ISR + + ; the PIO does not have a increment instruction, so to do that we do a + ; negate, decrement, negate sequence +increment: + MOV Y, ~Y + JMP Y--, increment_cont +increment_cont: + MOV Y, ~Y +.wrap ; the .wrap here avoids one jump instruction and saves a cycle too + + + +% c-sdk { + +#include "hardware/clocks.h" +#include "hardware/gpio.h" + +// max_step_rate is used to lower the clock of the state machine to save power +// if the application doesn't require a very high sampling rate. Passing zero +// will set the clock to the maximum + +static inline void quadrature_encoder_program_init(PIO pio, uint sm, uint pin, int max_step_rate) +{ + pio_sm_set_consecutive_pindirs(pio, sm, pin, 2, false); + pio_gpio_init(pio, pin); + pio_gpio_init(pio, pin + 1); + + gpio_pull_up(pin); + gpio_pull_up(pin + 1); + + pio_sm_config c = quadrature_encoder_program_get_default_config(0); + + sm_config_set_in_pins(&c, pin); // for WAIT, IN + sm_config_set_jmp_pin(&c, pin); // for JMP + // shift to left, autopull disabled + sm_config_set_in_shift(&c, false, false, 32); + // don't join FIFO's + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_NONE); + + // passing "0" as the sample frequency, + if (max_step_rate == 0) { + sm_config_set_clkdiv(&c, 1.0); + } else { + // one state machine loop takes at most 10 cycles + float div = (float)clock_get_hz(clk_sys) / (10 * max_step_rate); + sm_config_set_clkdiv(&c, div); + } + + pio_sm_init(pio, sm, 0, &c); + pio_sm_set_enabled(pio, sm, true); +} + +static inline int32_t quadrature_encoder_get_count(PIO pio, uint sm) +{ + uint ret; + int n; + + // if the FIFO has N entries, we fetch them to drain the FIFO, + // plus one entry which will be guaranteed to not be stale + n = pio_sm_get_rx_fifo_level(pio, sm) + 1; + while (n > 0) { + ret = pio_sm_get_blocking(pio, sm); + n--; + } + return ret; +} + +%} \ No newline at end of file diff --git a/src/pico/xinput_device.cpp b/src/pico/xinput_device.cpp index 78d8eb7b6..ce290f769 100644 --- a/src/pico/xinput_device.cpp +++ b/src/pico/xinput_device.cpp @@ -12,6 +12,7 @@ #include "device/usbd_pvt.h" #include "hid.h" #include "xinput_device.h" +#include //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF @@ -59,7 +60,7 @@ bool tud_xusb_n_report(uint8_t itf, void const *report, uint8_t len) { memcpy(p_xinput->epin_buf, report, len); sending = true; - return usbd_edpt_xfer(TUD_OPT_RHPORT, p_xinput->ep_in, p_xinput->epin_buf, len); + return usbd_edpt_xfer(TUD_OPT_RHPORT, p_xinput->ep_in, p_xinput->epin_buf, len, false); } bool tud_xinput_n_report(uint8_t itf, uint8_t report_id, void const *report, @@ -84,7 +85,7 @@ bool tud_xinput_n_report(uint8_t itf, uint8_t report_id, void const *report, } sending = true; return usbd_edpt_xfer(TUD_OPT_RHPORT, p_xinput->ep_in, p_xinput->epin_buf, - len); + len, false); } bool tud_xinput_n_boot_mode(uint8_t itf) { return _xinputd_itf[itf].boot_mode; } @@ -121,10 +122,26 @@ uint16_t xinputd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, } TU_VERIFY(p_xinput, 0); uint8_t const *p_desc = (uint8_t const *)itf_desc; - if (itf_desc->bInterfaceSubClass == 0x5D && - (itf_desc->bInterfaceProtocol == 0x01 || - itf_desc->bInterfaceProtocol == 0x03 || - itf_desc->bInterfaceProtocol == 0x02)) { + + if (itf_desc->bInterfaceSubClass == 0x01 && itf_desc->bInterfaceProtocol == 0xFF) { + p_desc = tu_desc_next(p_desc); + printf("Opened: %d\r\n", itf_desc->bNumEndpoints); + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, itf_desc->bNumEndpoints, + TUSB_XFER_INTERRUPT, &p_xinput->ep_out, + &p_xinput->ep_in), + 0); + printf("Opened: %02x %02x\r\n", p_xinput->ep_out, p_xinput->ep_in); + if (p_xinput->ep_out) { + if (!usbd_edpt_xfer(rhport, p_xinput->ep_out, p_xinput->epout_buf, sizeof(p_xinput->epout_buf), false)) { + TU_LOG_FAILED(); + TU_BREAKPOINT(); + } + } + return drv_len; + } else if (itf_desc->bInterfaceSubClass == 0x5D && + (itf_desc->bInterfaceProtocol == 0x01 || + itf_desc->bInterfaceProtocol == 0x03 || + itf_desc->bInterfaceProtocol == 0x02)) { // Xinput reserved endpoint //-------------- Xinput Descriptor --------------// p_desc = tu_desc_next(p_desc); @@ -140,7 +157,7 @@ uint16_t xinputd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, p_xinput->itf_num = itf_desc->bInterfaceNumber; if (p_xinput->ep_out) { - if (!usbd_edpt_xfer(rhport, p_xinput->ep_out, p_xinput->epout_buf, sizeof(p_xinput->epout_buf))) { + if (!usbd_edpt_xfer(rhport, p_xinput->ep_out, p_xinput->epout_buf, sizeof(p_xinput->epout_buf), false)) { TU_LOG_FAILED(); TU_BREAKPOINT(); } @@ -164,14 +181,13 @@ uint16_t xinputd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, // Prepare for output endpoint if (p_xinput->ep_out) { - if (!usbd_edpt_xfer(rhport, p_xinput->ep_out, p_xinput->epout_buf, sizeof(p_xinput->epout_buf))) { + if (!usbd_edpt_xfer(rhport, p_xinput->ep_out, p_xinput->epout_buf, sizeof(p_xinput->epout_buf), false)) { TU_LOG_FAILED(); TU_BREAKPOINT(); } } } } else if (0x58 == itf_desc->bInterfaceClass) { - // len = interface + n*endpoints drv_len = sizeof(tusb_desc_interface_t) + itf_desc->bNumEndpoints * sizeof(tusb_desc_endpoint_t); TU_ASSERT(max_len >= drv_len, 0); @@ -197,7 +213,7 @@ uint16_t xinputd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, // Prepare for output endpoint if (p_hid->ep_out) { - if (!usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))) { + if (!usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf), false)) { TU_LOG_FAILED(); TU_BREAKPOINT(); } @@ -234,7 +250,7 @@ uint16_t xinputd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, // Prepare for output endpoint if (p_hid->ep_out) { - if (!usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))) { + if (!usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf), false)) { TU_LOG_FAILED(); TU_BREAKPOINT(); } @@ -263,16 +279,19 @@ bool xinputd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, hid_set_report(p_xinput->epout_buf, xferred_bytes, 0x00, INTERRUPT_ID); if (consoleType == XBOX360 || consoleType == WINDOWS || consoleType == OG_XBOX) { TU_ASSERT(usbd_edpt_xfer(rhport, p_xinput->ep_out, p_xinput->epout_buf, - 0x20)); - -#if USB_HOST_STACK + 0x20, false)); } else if (consoleType == XBOXONE) { TU_ASSERT(usbd_edpt_xfer(rhport, p_xinput->ep_out, p_xinput->epout_buf, - 0x40)); -#endif + 0x40, false)); + } else if (consoleType == ARCADE) { + TU_ASSERT(usbd_edpt_xfer(rhport, p_xinput->ep_out, p_xinput->epout_buf, + 0x40, false)); + } else if (consoleType == PS5) { + TU_ASSERT(usbd_edpt_xfer(rhport, p_xinput->ep_out, p_xinput->epout_buf, + 0x40, false)); } else { TU_ASSERT(usbd_edpt_xfer(rhport, p_xinput->ep_out, p_xinput->epout_buf, - 0x08)); + 0x08, false)); } } else if (ep_addr == p_xinput->ep_in) { diff --git a/src/pico/xinput_host.cpp b/src/pico/xinput_host.cpp index acf511fdc..0c5dadd54 100644 --- a/src/pico/xinput_host.cpp +++ b/src/pico/xinput_host.cpp @@ -75,12 +75,15 @@ static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr); // Interface API //--------------------------------------------------------------------+ -uint8_t tuh_xinput_instance_count(uint8_t dev_addr) { +uint8_t tuh_xinput_instance_count(uint8_t dev_addr) +{ return get_dev(dev_addr)->inst_count; } -bool tuh_xinput_mounted(uint8_t dev_addr, uint8_t instance) { - if (get_dev(dev_addr)->inst_count < instance) return false; +bool tuh_xinput_mounted(uint8_t dev_addr, uint8_t instance) +{ + if (get_dev(dev_addr)->inst_count < instance) + return false; xinputh_interface_t *hid_itf = get_instance(dev_addr, instance); return (hid_itf->ep_in != 0) || (hid_itf->ep_out != 0); } @@ -89,13 +92,15 @@ bool tuh_xinput_mounted(uint8_t dev_addr, uint8_t instance) { // Interrupt Endpoint API //--------------------------------------------------------------------+ -bool tuh_xinput_receive_report(uint8_t dev_addr, uint8_t instance) { +bool tuh_xinput_receive_report(uint8_t dev_addr, uint8_t instance) +{ xinputh_interface_t *hid_itf = get_instance(dev_addr, instance); // claim endpoint TU_VERIFY(usbh_edpt_claim(dev_addr, hid_itf->ep_in)); - if (!usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size)) { + if (!usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size)) + { usbh_edpt_release(dev_addr, hid_itf->ep_in); return false; } @@ -103,19 +108,22 @@ bool tuh_xinput_receive_report(uint8_t dev_addr, uint8_t instance) { return true; } -bool tuh_xinput_ready(uint8_t dev_addr, uint8_t instance) { +bool tuh_xinput_ready(uint8_t dev_addr, uint8_t instance) +{ TU_VERIFY(tuh_xinput_mounted(dev_addr, instance)); xinputh_interface_t *hid_itf = get_instance(dev_addr, instance); return !usbh_edpt_busy(dev_addr, hid_itf->ep_in); } -bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { +bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) +{ xinputh_interface_t *hid_itf = get_instance(dev_addr, instance); // claim endpoint TU_VERIFY(usbh_edpt_claim(dev_addr, hid_itf->ep_out)); memcpy(hid_itf->epout_buf, report, len); - if (!usbh_edpt_xfer(dev_addr, hid_itf->ep_out, hid_itf->epout_buf, len)) { + if (!usbh_edpt_xfer(dev_addr, hid_itf->ep_out, hid_itf->epout_buf, len)) + { usbh_edpt_release(dev_addr, hid_itf->ep_out); return false; } @@ -125,43 +133,52 @@ bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, uint8_t const *r //--------------------------------------------------------------------+ // USBH API //--------------------------------------------------------------------+ -bool xinputh_init(void) { +bool xinputh_init(void) +{ tu_memclr(_xinputh_dev, sizeof(_xinputh_dev)); return true; } - -void fill_generic_report_host(uint8_t dev_addr, uint8_t instance, const uint8_t *report, USB_Host_Data_t *out) { +void fill_generic_report_host(uint8_t dev_addr, uint8_t instance, const uint8_t *report, USB_Host_Data_t *out) +{ memset(out, 0, sizeof(USB_Host_Data_t)); xinputh_interface_t *hid_itf = get_instance(dev_addr, instance); fill_generic_report(hid_itf->info, report, out); } -bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { +bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ (void)result; uint8_t const dir = tu_edpt_dir(ep_addr); uint8_t const instance = get_instance_id_by_epaddr(dev_addr, ep_addr); xinputh_interface_t *hid_itf = get_instance(dev_addr, instance); - if (dir == TUSB_DIR_IN) { + if (dir == TUSB_DIR_IN) + { usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size); tuh_xinput_report_received_cb(dev_addr, instance, hid_itf->epin_buf, (uint16_t)xferred_bytes); - } else { + } + else + { tuh_xinput_report_sent_cb(dev_addr, instance, hid_itf->epin_buf, (uint16_t)xferred_bytes); } return true; } -void xinputh_close(uint8_t dev_addr) { +void xinputh_close(uint8_t dev_addr) +{ TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); xinputh_device_t *hid_dev = get_dev(dev_addr); - for (uint8_t inst = 0; inst < hid_dev->inst_count; inst++) { - if (tuh_xinput_umount_cb) { + for (uint8_t inst = 0; inst < hid_dev->inst_count; inst++) + { + if (tuh_xinput_umount_cb) + { tuh_xinput_umount_cb(dev_addr, inst); } - if (hid_dev->instances[inst].info != NULL) { + if (hid_dev->instances[inst].info != NULL) + { USB_FreeReportInfo(hid_dev->instances[inst].info); } } @@ -169,25 +186,27 @@ void xinputh_close(uint8_t dev_addr) { tu_memclr(hid_dev, sizeof(xinputh_device_t)); } - //--------------------------------------------------------------------+ // Enumeration //--------------------------------------------------------------------+ -extern uint8_t transfer_with_usb_controller(const uint8_t dev_addr, const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t wLength, uint8_t *buffer, bool* status); -bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { +extern uint8_t transfer_with_usb_controller(const uint8_t dev_addr, const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t wLength, uint8_t *buffer, bool *status); +uint16_t xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +{ (void)rhport; (void)max_len; - if (dev_addr == 9) { + if (dev_addr == 9) + { return false; } - // Some controllers need a delay here otherwise they don't initialise properly - sleep_ms(1); TU_VERIFY(0x58 == desc_itf->bInterfaceClass || TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass || TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); + TU_VERIFY(desc_itf->bAlternateSetting == 0, 0); xinputh_interface_t *p_xinput = NULL; uint8_t i = 0; - for (; i < CFG_TUH_XINPUT; i++) { + for (; i < CFG_TUH_XINPUT; i++) + { xinputh_interface_t *hid_itf = get_instance(dev_addr, i); - if (hid_itf->ep_in == 0 && hid_itf->ep_out == 0) { + if (hid_itf->ep_in == 0 && hid_itf->ep_out == 0) + { p_xinput = hid_itf; break; } @@ -196,7 +215,8 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const uint16_t drv_len = sizeof(tusb_desc_interface_t) + (desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); // Support standard HID devices - if (TUSB_CLASS_HID == desc_itf->bInterfaceClass) { + if (TUSB_CLASS_HID == desc_itf->bInterfaceClass) + { TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); uint8_t const *p_desc = (uint8_t const *)desc_itf; // Xinput reserved endpoint @@ -207,17 +227,20 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const TU_ASSERT(HID_DESCRIPTOR_HID == x_desc->bDescriptorType, 0); drv_len += x_desc->bLength; uint8_t endpoints = desc_itf->bNumEndpoints; - while (endpoints--) { + while (endpoints--) + { p_desc = tu_desc_next(p_desc); tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)p_desc; TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - if (desc_ep->bEndpointAddress & 0x80) { + if (desc_ep->bEndpointAddress & 0x80) + { p_xinput->ep_in = desc_ep->bEndpointAddress; p_xinput->epin_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); - usbh_edpt_xfer(dev_addr, p_xinput->ep_in, p_xinput->epin_buf, p_xinput->epin_size); - } else { + } + else + { p_xinput->ep_out = desc_ep->bEndpointAddress; p_xinput->epout_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); @@ -226,21 +249,25 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const p_xinput->itf_num = desc_itf->bInterfaceNumber; p_xinput->type = GENERIC; - if (desc_itf->bInterfaceProtocol == HID_ITF_PROTOCOL_KEYBOARD) { + if (desc_itf->bInterfaceProtocol == HID_ITF_PROTOCOL_KEYBOARD) + { p_xinput->type = KEYBOARD; } - if (desc_itf->bInterfaceProtocol == HID_ITF_PROTOCOL_MOUSE) { + if (desc_itf->bInterfaceProtocol == HID_ITF_PROTOCOL_MOUSE) + { p_xinput->type = MOUSE; } // TODO: do we support nkro - if (p_xinput->type == GENERIC) { + if (p_xinput->type == GENERIC) + { uint8_t temp_buf[512]; uint8_t *current = temp_buf; uint8_t len = x_desc->wDescriptorLength; uint8_t last_id = 0; tuh_descriptor_get_hid_report(dev_addr, p_xinput->itf_num, x_desc->bDescrType, 0, temp_buf, x_desc->wDescriptorLength, NULL, (uintptr_t)temp_buf); // Seems that sometimes we miss the first byte? - if (!temp_buf[0] || temp_buf[0] == 4) { + if (!temp_buf[0] || temp_buf[0] == 4) + { temp_buf[0] = 0x05; } // printf("Report: \r\n"); @@ -252,38 +279,76 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const foundPS4 = false; foundPS5 = false; USB_ProcessHIDReport(temp_buf, x_desc->wDescriptorLength, &p_xinput->info); - if (foundPS5) { + if (foundPS5) + { p_xinput->type = PS5; } - if (foundPS4) { + if (foundPS4) + { p_xinput->type = PS4; } - if (foundPS3) { + if (foundPS3) + { p_xinput->type = PS3; } } _xinputh_dev->inst_count++; tuh_xinput_receive_report(dev_addr, i); p_xinput->subtype = GAMEPAD; - return true; + return drv_len; } - uint8_t const *p_desc = (uint8_t const *)desc_itf; + if (0xFF == desc_itf->bInterfaceClass && desc_itf->bInterfaceSubClass == 0x00 && + desc_itf->bInterfaceProtocol == 0x00) + { + uint8_t endpoints = desc_itf->bNumEndpoints; + while (endpoints--) + { + p_desc = tu_desc_next(p_desc); + tusb_desc_endpoint_t const *desc_ep = + (tusb_desc_endpoint_t const *)p_desc; + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); + if (desc_ep->bEndpointAddress & 0x80) + { + p_xinput->ep_in = desc_ep->bEndpointAddress; + p_xinput->epin_size = desc_ep->wMaxPacketSize; + TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); + usbh_edpt_xfer(dev_addr, p_xinput->ep_in, p_xinput->epin_buf, p_xinput->epin_size); + } + else + { + p_xinput->ep_out = desc_ep->bEndpointAddress; + p_xinput->epout_size = desc_ep->wMaxPacketSize; + TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); + } + } + p_xinput->itf_num = desc_itf->bInterfaceNumber; + + p_xinput->type = SWITCH2; + p_xinput->subtype = NON_CONTROLLER; + return drv_len; + } + if (desc_itf->bInterfaceSubClass == 0x5D && - desc_itf->bInterfaceProtocol == 0x04) { + desc_itf->bInterfaceProtocol == 0x04) + { // Big button uint8_t endpoints = desc_itf->bNumEndpoints; - while (endpoints--) { + while (endpoints--) + { p_desc = tu_desc_next(p_desc); tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)p_desc; TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - if (desc_ep->bEndpointAddress & 0x80) { + if (desc_ep->bEndpointAddress & 0x80) + { p_xinput->ep_in = desc_ep->bEndpointAddress; p_xinput->epin_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); usbh_edpt_xfer(dev_addr, p_xinput->ep_in, p_xinput->epin_buf, p_xinput->epin_size); - } else { + } + else + { p_xinput->ep_out = desc_ep->bEndpointAddress; p_xinput->epout_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); @@ -293,11 +358,13 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const p_xinput->type = XBOX360_BB; p_xinput->subtype = GAMEPAD; - return true; - } else if (desc_itf->bInterfaceSubClass == 0x5D && - (desc_itf->bInterfaceProtocol == 0x01 || - desc_itf->bInterfaceProtocol == 0x03 || - desc_itf->bInterfaceProtocol == 0x02)) { + return drv_len; + } + else if (desc_itf->bInterfaceSubClass == 0x5D && + (desc_itf->bInterfaceProtocol == 0x01 || + desc_itf->bInterfaceProtocol == 0x03 || + desc_itf->bInterfaceProtocol == 0x02)) + { // Xinput reserved endpoint //-------------- Xinput Descriptor --------------// p_desc = tu_desc_next(p_desc); @@ -306,16 +373,20 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const TU_ASSERT(XINPUT_DESC_TYPE_RESERVED == x_desc->bDescriptorType, 0); drv_len += x_desc->bLength; uint8_t endpoints = desc_itf->bNumEndpoints; - while (endpoints--) { + while (endpoints--) + { p_desc = tu_desc_next(p_desc); tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)p_desc; TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - if (desc_ep->bEndpointAddress & 0x80) { + if (desc_ep->bEndpointAddress & 0x80) + { p_xinput->ep_in = desc_ep->bEndpointAddress; p_xinput->epin_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); - } else { + } + else + { p_xinput->ep_out = desc_ep->bEndpointAddress; p_xinput->epout_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); @@ -324,17 +395,21 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const p_xinput->itf_num = desc_itf->bInterfaceNumber; p_xinput->type = XBOX360; p_xinput->subtype = GAMEPAD; - if (desc_itf->bInterfaceProtocol == 0x01) { + if (desc_itf->bInterfaceProtocol == 0x01) + { p_xinput->subtype = x_desc->subtype; usbh_edpt_xfer(dev_addr, p_xinput->ep_in, p_xinput->epin_buf, p_xinput->epin_size); - } else { + } + else + { p_xinput->type = NON_CONTROLLER; } _xinputh_dev->inst_count++; - return true; - - } else if (desc_itf->bInterfaceSubClass == 0xfD && - desc_itf->bInterfaceProtocol == 0x13) { + return drv_len; + } + else if (desc_itf->bInterfaceSubClass == 0xfD && + desc_itf->bInterfaceProtocol == 0x13) + { // Xinput reserved endpoint //-------------- Xinput Descriptor --------------// p_desc = tu_desc_next(p_desc); @@ -347,20 +422,26 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const p_xinput->subtype = GAMEPAD; p_xinput->itf_num = desc_itf->bInterfaceNumber; _xinputh_dev->inst_count++; - return true; - } else if (desc_itf->bInterfaceSubClass == 0x47 && - desc_itf->bInterfaceProtocol == 0xD0 && desc_itf->bNumEndpoints) { + return drv_len; + } + else if (desc_itf->bInterfaceSubClass == 0x47 && + desc_itf->bInterfaceProtocol == 0xD0 && desc_itf->bNumEndpoints) + { uint8_t endpoints = desc_itf->bNumEndpoints; - while (endpoints--) { + while (endpoints--) + { p_desc = tu_desc_next(p_desc); tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)p_desc; TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - if (desc_ep->bEndpointAddress & 0x80) { + if (desc_ep->bEndpointAddress & 0x80) + { p_xinput->ep_in = desc_ep->bEndpointAddress; p_xinput->epin_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); - } else { + } + else + { p_xinput->ep_out = desc_ep->bEndpointAddress; p_xinput->epout_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); @@ -371,22 +452,31 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const p_xinput->subtype = GAMEPAD; _xinputh_dev->inst_count++; usbh_edpt_xfer(dev_addr, p_xinput->ep_in, p_xinput->epin_buf, p_xinput->epin_size); - return true; - } else if (desc_itf->bInterfaceSubClass == 0x5D && - desc_itf->bInterfaceProtocol == 0x81) { + return drv_len; + } + else if (desc_itf->bInterfaceSubClass == 0x5D && + desc_itf->bInterfaceProtocol == 0x81) + { // Skip over 0x22 descriptor p_desc = tu_desc_next(p_desc); + XBOX_ID_DESCRIPTOR *x_desc = + (XBOX_ID_DESCRIPTOR *)p_desc; + drv_len += x_desc->bLength; uint8_t endpoints = desc_itf->bNumEndpoints; - while (endpoints--) { + while (endpoints--) + { p_desc = tu_desc_next(p_desc); tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)p_desc; TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - if (desc_ep->bEndpointAddress & 0x80) { + if (desc_ep->bEndpointAddress & 0x80) + { p_xinput->ep_in = desc_ep->bEndpointAddress; p_xinput->epin_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); - } else { + } + else + { p_xinput->ep_out = desc_ep->bEndpointAddress; p_xinput->epout_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); @@ -397,20 +487,26 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const p_xinput->subtype = UNKNOWN; _xinputh_dev->inst_count++; usbh_edpt_xfer(dev_addr, p_xinput->ep_in, p_xinput->epin_buf, p_xinput->epin_size); - return true; - } else if (desc_itf->bInterfaceClass == 0x58) { + return drv_len; + } + else if (desc_itf->bInterfaceClass == 0x58) + { uint8_t endpoints = desc_itf->bNumEndpoints; - while (endpoints--) { + while (endpoints--) + { p_desc = tu_desc_next(p_desc); tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)p_desc; TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - if (desc_ep->bEndpointAddress & 0x80) { + if (desc_ep->bEndpointAddress & 0x80) + { p_xinput->ep_in = desc_ep->bEndpointAddress; p_xinput->epin_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); usbh_edpt_xfer(dev_addr, p_xinput->ep_in, p_xinput->epin_buf, p_xinput->epin_size); - } else { + } + else + { p_xinput->ep_out = desc_ep->bEndpointAddress; p_xinput->epout_size = desc_ep->wMaxPacketSize; TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); @@ -420,8 +516,8 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const p_xinput->type = OG_XBOX; p_xinput->subtype = GAMEPAD; - return true; - } + return drv_len; + } return false; } @@ -429,7 +525,8 @@ bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const // Set Configure //--------------------------------------------------------------------+ -enum { +enum +{ CONFG_SET_IDLE, CONFIG_SET_PROTOCOL, CONFIG_GET_REPORT_DESC, @@ -439,19 +536,24 @@ enum { static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance); static void process_set_config(tuh_xfer_t *xfer); -bool xinputh_set_config(uint8_t dev_addr, uint8_t itf_num) { +bool xinputh_set_config(uint8_t dev_addr, uint8_t itf_num) +{ uint8_t instance = get_instance_id_by_itfnum(dev_addr, itf_num); config_driver_mount_complete(dev_addr, instance); return true; } -static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance) { +static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance) +{ xinputh_interface_t *hid_itf = get_instance(dev_addr, instance); // enumeration is complete - tuh_xinput_mount_cb(dev_addr, instance, hid_itf->type, hid_itf->subtype); + tuh_xinput_mount_cb(dev_addr, instance, hid_itf->itf_num, hid_itf->type, hid_itf->subtype); // notify usbh that driver enumeration is complete usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num); + if (hid_itf->ep_in) { + usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size); + } } //--------------------------------------------------------------------+ @@ -459,32 +561,40 @@ static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance) { //--------------------------------------------------------------------+ // Get Device by address -TU_ATTR_ALWAYS_INLINE static inline xinputh_device_t *get_dev(uint8_t dev_addr) { +TU_ATTR_ALWAYS_INLINE static inline xinputh_device_t *get_dev(uint8_t dev_addr) +{ return &_xinputh_dev[dev_addr - 1]; } // Get Interface by instance number -TU_ATTR_ALWAYS_INLINE static inline xinputh_interface_t *get_instance(uint8_t dev_addr, uint8_t instance) { +TU_ATTR_ALWAYS_INLINE static inline xinputh_interface_t *get_instance(uint8_t dev_addr, uint8_t instance) +{ return &_xinputh_dev[dev_addr - 1].instances[instance]; } // Get instance ID by interface number -static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf) { - for (uint8_t inst = 0; inst < CFG_TUH_XINPUT; inst++) { +static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf) +{ + for (uint8_t inst = 0; inst < CFG_TUH_XINPUT; inst++) + { xinputh_interface_t *hid = get_instance(dev_addr, inst); - if ((hid->itf_num == itf)) return inst; + if ((hid->itf_num == itf)) + return inst; } return 0xff; } // Get instance ID by endpoint address -static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr) { - for (uint8_t inst = 0; inst < CFG_TUH_XINPUT; inst++) { +static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr) +{ + for (uint8_t inst = 0; inst < CFG_TUH_XINPUT; inst++) + { xinputh_interface_t *hid = get_instance(dev_addr, inst); - if ((ep_addr == hid->ep_in) || (ep_addr == hid->ep_out)) return inst; + if ((ep_addr == hid->ep_in) || (ep_addr == hid->ep_out)) + return inst; } return 0xff; diff --git a/src/pico/xinput_host.h b/src/pico/xinput_host.h index 695bce2fa..00d68ac09 100644 --- a/src/pico/xinput_host.h +++ b/src/pico/xinput_host.h @@ -118,7 +118,7 @@ bool tuh_xinput_receive_report(uint8_t dev_addr, uint8_t instance); // can be used to parse common/simple enough descriptor. // Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped // therefore report_desc = NULL, desc_len = 0 -bool tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t type, uint8_t subtype); +bool tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t itf_num, uint8_t type, uint8_t subtype); bool tuh_xinput_ready(uint8_t dev_addr, uint8_t instance); bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len); @@ -143,7 +143,7 @@ TU_ATTR_WEAK void tuh_xinput_set_protocol_complete_cb(uint8_t dev_addr, uint8_t // Internal Class Driver API //--------------------------------------------------------------------+ bool xinputh_init(void); -bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const* desc_itf, uint16_t max_len); +uint16_t xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const* desc_itf, uint16_t max_len); bool xinputh_set_config(uint8_t dev_addr, uint8_t itf_num); bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); void xinputh_close(uint8_t dev_addr); diff --git a/src/pico_slave/main.cpp b/src/pico_slave/main.cpp index 4dc6b8fa9..90529d6f8 100644 --- a/src/pico_slave/main.cpp +++ b/src/pico_slave/main.cpp @@ -2,6 +2,9 @@ #include #include #include +#include "hardware/pio.h" +#include "hardware/timer.h" +#include "quadrature_encoder.pio.h" #include "io.h" #include "pico_slave.h" @@ -16,10 +19,19 @@ volatile uint32_t mask = 0; volatile uint8_t wtS0Pin = 0; volatile uint8_t wtS1Pin = 0; volatile uint8_t wtS2Pin = 0; +volatile uint8_t quadAPin = 0; volatile uint16_t wt_sensitivity = 0; volatile uint8_t rawWt; volatile uint32_t lastWt[5] = {0}; +volatile bool wtShouldInit = false; +volatile bool quadShouldInit = false; volatile bool hasInitWt = false; +volatile bool hasInitQuad = false; +volatile int quadPollRate = 0; +volatile int32_t new_value, delta, old_value = 0; +volatile int32_t last_value = -1, last_delta = -1; +PIO pio = pio0; +const uint sm = 0; spi_inst_t* hardware; void recv(int len) { command = WIRE.read(); @@ -106,6 +118,13 @@ void recv(int len) { mask = (1 << wtS0Pin) | (1 << wtS1Pin) | (1 << wtS2Pin); wt_sensitivity = WIRE.read() << 8 | WIRE.read(); hasInitWt = false; + wtShouldInit = true; + break; + case SLAVE_COMMAND_INIT_QUAD: + quadAPin = WIRE.read(); + quadPollRate = WIRE.read(); + hasInitQuad = false; + quadShouldInit = true; break; } } @@ -122,6 +141,10 @@ void req() { WIRE.write((uint8_t*)&rawWt, sizeof(rawWt)); break; } + case SLAVE_COMMAND_GET_QUAD: { + WIRE.write((uint8_t*)&delta, sizeof(delta)); + break; + } case SLAVE_COMMAND_GET_WT_RAW: { volatile uint8_t* data = (volatile uint8_t*)lastWt; for (uint8_t i = 0; i < sizeof(lastWt); i++) { @@ -172,9 +195,9 @@ uint32_t readWtSlave(int pin) { bool checkWtSlave(int pin) { return readWtSlave(pin) > initialWt[pin]; } - +uint32_t lastQuadPoll = 0; void loop() { - if (wtS2Pin && !hasInitWt) { + if (wtShouldInit && !hasInitWt) { hasInitWt = true; memset(initialWt, 0, sizeof(initialWt)); for (int j = 0; j < 1000; j++) { @@ -187,10 +210,20 @@ void loop() { initialWt[i] += wt_sensitivity; } } + if (quadShouldInit && !hasInitQuad) { + hasInitQuad = true; + quadrature_encoder_program_init(pio, sm, quadAPin, 0); + } if (hasInitWt) { checkWtSlave(6); rawWt = checkWtSlave(1) | (checkWtSlave(0) << 1) | (checkWtSlave(2) << 2) | (checkWtSlave(3) << 3) | (checkWtSlave(4) << 4); } + if (hasInitQuad && (millis()-lastQuadPoll) > quadPollRate) { + lastQuadPoll = millis(); + new_value = quadrature_encoder_get_count(pio, sm); + delta = new_value - old_value; + old_value = new_value; + } } void setup() { #ifdef TWI_1_SDA @@ -213,4 +246,5 @@ void setup() { WIRE.begin(SLAVE_ADDR); WIRE.onReceive(recv); WIRE.onRequest(req); + pio_add_program(pio, &quadrature_encoder_program); } \ No newline at end of file diff --git a/src/shared/config/config.c b/src/shared/config/config.c index ce329c293..6c1502f0d 100644 --- a/src/shared/config/config.c +++ b/src/shared/config/config.c @@ -12,25 +12,22 @@ const uint8_t* config = (uint8_t*)0x100A3000; const uint8_t PROGMEM config[CONFIGURATION_LEN] = CONFIGURATION; #endif uint8_t consoleType = 0xFF; +uint8_t arcadeSide = 1; +uint8_t proGuitarType = DEVICE_TYPE; #if DEVICE_TYPE_IS_GUITAR -const uint8_t announce[] = {0x02, 0x20, 0x01, 0x1c, 0x7e, 0xed, 0x81, TEMP, TEMP, TEMP, 0x00, 0x00, 0x38, 0x07, 0x61, 0x41, 0x01, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00}; -const uint8_t xb1_descriptor[] = {0x04, 0xf0, 0x01, 0x3a, 0xe5, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x00, 0xa6, 0x00, 0x16, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x23, 0x00, 0x29, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x05, 0x01, 0x04, 0x05, 0x06, 0x0a, 0x02, 0x04, 0xa0, 0x01, 0xba, 0x00, 0x3a, 0x20, 0x00, 0x4d, 0x61, 0x64, 0x43, 0x61, 0x74, 0x7a, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x47, 0x75, 0x69, 0x74, 0x61, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x63, 0x61, 0x73, 0x74, 0x65, 0x72, 0x27, 0x00, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x4e, 0x61, 0x76, 0x04, 0xa0, 0x01, 0xba, 0x00, 0x74, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x03, 0x38, 0xe4, 0x2a, 0x0d, 0x7d, 0x7f, 0x33, 0x49, 0x86, 0x93, 0x30, 0xfc, 0x55, 0x01, 0x8e, 0x77, 0xe7, 0x1f, 0xf3, 0xb8, 0x86, 0x73, 0xe9, 0x40, 0xa9, 0xf8, 0x2f, 0x21, 0x26, 0x3a, 0xcf, 0xb7, 0x56, 0xff, 0x76, 0x97, 0xfd, 0x9b, 0x81, 0x45, 0x04, 0xb0, 0x01, 0x37, 0xae, 0x01, 0xad, 0x45, 0xb6, 0x45, 0xbb, 0xa5, 0x26, 0xd6, 0x02, 0x17, 0x00, 0x20, 0x0e, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x21, 0x05, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const uint8_t xb1_descriptor_end[] = {0x04, 0xa0, 0x01, 0x00, 0xe5, 0x01}; +const uint8_t announce[] = {0x02, 0x20, 0x01, 0x1c, 0x7e, 0xed, 0x81, TEMP, TEMP, TEMP, 0x00, 0x00, 0x6f, 0x0e, 0x48, 0x02, 0x01, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00}; +const uint8_t xb1_descriptor[] = {0x04, 0xf0, 0x01, 0x3a, 0xf5, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00, 0xb6, 0x00, 0x16, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x23, 0x00, 0x29, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x05, 0x01, 0x04, 0x05, 0x06, 0x0a, 0x02, 0x04, 0xa0, 0x01, 0xba, 0x00, 0x3a, 0x20, 0x00, 0x4d, 0x61, 0x64, 0x43, 0x61, 0x74, 0x7a, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x47, 0x75, 0x69, 0x74, 0x61, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x63, 0x61, 0x73, 0x74, 0x65, 0x72, 0x27, 0x00, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x4e, 0x61, 0x76, 0x04, 0xa0, 0x01, 0xba, 0x00, 0x74, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x04, 0x38, 0xe4, 0x2a, 0x0d, 0x7d, 0x7f, 0x33, 0x49, 0x86, 0x93, 0x30, 0xfc, 0x55, 0x01, 0x8e, 0x77, 0xe7, 0x1f, 0xf3, 0xb8, 0x86, 0x73, 0xe9, 0x40, 0xa9, 0xf8, 0x2f, 0x21, 0x26, 0x3a, 0xcf, 0xb7, 0x56, 0xff, 0x76, 0x97, 0xfd, 0x9b, 0x81, 0x45, 0x04, 0xa0, 0x01, 0x3a, 0xae, 0x01, 0xad, 0x45, 0xb6, 0x45, 0xbb, 0xa5, 0x26, 0xd6, 0x77, 0xce, 0x34, 0x7a, 0xe2, 0x7d, 0xc6, 0x45, 0x8c, 0xa4, 0x00, 0x42, 0xc0, 0x8b, 0xd9, 0x4a, 0x02, 0x17, 0x00, 0x20, 0x20, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x21, 0x05, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x04, 0xb0, 0x01, 0x0d, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +const uint8_t xb1_descriptor_end[] = {0x04, 0xa0, 0x01, 0x00, 0xf5, 0x01}; #elif DEVICE_TYPE_IS_DRUM -const uint8_t announce[] = {0x02, 0x20, 0x01, 0x1c, 0x7e, 0xed, 0x81, TEMP, TEMP, TEMP, 0x00, 0x00, 0x38, 0x07, 0x62, 0x42, 0x01, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00}; -const uint8_t xb1_descriptor[] = {0x04, 0xf0, 0x01, 0x3a, 0xc5, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x9d, 0x00, 0x16, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x23, 0x00, 0x29, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x05, 0x01, 0x04, 0x05, 0x06, 0x0a, 0x02, 0x04, 0xa0, 0x01, 0xba, 0x00, 0x3a, 0x17, 0x00, 0x4d, 0x61, 0x64, 0x43, 0x61, 0x74, 0x7a, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x44, 0x72, 0x75, 0x6d, 0x73, 0x2e, 0x47, 0x6c, 0x61, 0x6d, 0x27, 0x00, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x4e, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x04, 0xa0, 0x01, 0xba, 0x00, 0x74, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x03, 0x93, 0x28, 0x18, 0x06, 0xe0, 0xcc, 0x85, 0x4b, 0x92, 0x71, 0x0a, 0x10, 0xdb, 0xab, 0x7e, 0x07, 0xe7, 0x1f, 0xf3, 0xb8, 0x86, 0x73, 0xe9, 0x40, 0xa9, 0xf8, 0x2f, 0x21, 0x26, 0x3a, 0xcf, 0xb7, 0x56, 0xff, 0x76, 0x97, 0xfd, 0x9b, 0x81, 0x45, 0xad, 0x45, 0xb6, 0x45, 0xbb, 0xa5, 0x26, 0xd6, 0x01, 0x04, 0xb0, 0x01, 0x17, 0xae, 0x01, 0x17, 0x00, 0x20, 0x0a, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const uint8_t xb1_descriptor_end[] = {0x04, 0xa0, 0x01, 0x00, 0xc5, 0x01}; +const uint8_t announce[] = {0x02, 0x20, 0x01, 0x1c, 0x7e, 0xed, 0x81, TEMP, TEMP, TEMP, 0x00, 0x00, 0x6f, 0x0e, 0x71, 0x01, 0x01, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00}; +const uint8_t xb1_descriptor[] = {0x04, 0xf0, 0x01, 0x3a, 0xd5, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, 0x00, 0xad, 0x00, 0x16, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x23, 0x00, 0x29, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x05, 0x01, 0x04, 0x05, 0x06, 0x0a, 0x02, 0x04, 0xa0, 0x01, 0xba, 0x00, 0x3a, 0x17, 0x00, 0x4d, 0x61, 0x64, 0x43, 0x61, 0x74, 0x7a, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x44, 0x72, 0x75, 0x6d, 0x73, 0x2e, 0x47, 0x6c, 0x61, 0x6d, 0x27, 0x00, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x4e, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x04, 0xa0, 0x01, 0xba, 0x00, 0x74, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x04, 0x93, 0x28, 0x18, 0x06, 0xe0, 0xcc, 0x85, 0x4b, 0x92, 0x71, 0x0a, 0x10, 0xdb, 0xab, 0x7e, 0x07, 0xe7, 0x1f, 0xf3, 0xb8, 0x86, 0x73, 0xe9, 0x40, 0xa9, 0xf8, 0x2f, 0x21, 0x26, 0x3a, 0xcf, 0xb7, 0x56, 0xff, 0x76, 0x97, 0xfd, 0x9b, 0x81, 0x45, 0xad, 0x45, 0xb6, 0x45, 0xbb, 0xa5, 0x26, 0xd6, 0x77, 0x04, 0xb0, 0x01, 0x27, 0xae, 0x01, 0xce, 0x34, 0x7a, 0xe2, 0x7d, 0xc6, 0x45, 0x8c, 0xa4, 0x00, 0x42, 0xc0, 0x8b, 0xd9, 0x4a, 0x01, 0x17, 0x00, 0x20, 0x0a, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +const uint8_t xb1_descriptor_end[] = {0x04, 0xa0, 0x01, 0x00, 0xd5, 0x01}; #elif DEVICE_TYPE_IS_LIVE_GUITAR const uint8_t announce[] = {0x02, 0x20, 0x01, 0x1C, 0x7B, 0xED, 0x63, TEMP, TEMP, TEMP, 0x00, 0x00, 0x30, 0x14, 0x9B, 0x07, 0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00}; -const uint8_t xb1_descriptor[] = {0x04, 0xF0, 0x01, 0x3A, 0xA5, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x01, 0xCF, 0x00, 0x16, 0x00, 0x1F, 0x00, 0x20, 0x00, 0x27, 0x00, 0x2D, 0x00, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x05, 0x01, 0x04, - 0x04, 0xA0, 0x01, 0xBA, 0x00, 0x3A, 0x05, 0x06, 0x0A, 0x03, 0x19, 0x00, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x58, 0x62, 0x6F, 0x78, 0x2E, 0x49, 0x6E, 0x70, 0x75, 0x74, 0x2E, 0x47, 0x48, 0x37, 0x1A, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x2E, 0x58, 0x62, 0x6F, 0x78, 0x2E, 0x49, 0x6E, 0x70, 0x75, 0x74, 0x2E, 0x47, 0x61, 0x6D, 0x65, 0x70, 0x61, - 0x04, 0xA0, 0x01, 0xBA, 0x00, 0x74, 0x64, 0x27, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x2E, 0x58, 0x62, 0x6F, 0x78, 0x2E, 0x49, 0x6E, 0x70, 0x75, 0x74, 0x2E, 0x4E, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x43, 0x6F, 0x6E, 0x74, 0x72, 0x6F, 0x6C, 0x6C, 0x65, 0x72, 0x04, 0xD9, 0xFD, 0x12, 0xFD, 0x73, 0x8E, 0xC7, 0x47, 0xA2, 0x31, 0x96, 0x26, 0x8C, 0x38, 0x00, - 0x04, 0xA0, 0x01, 0x3A, 0xAE, 0x01, 0x9A, 0x2C, 0x40, 0x2E, 0x08, 0xDF, 0x07, 0xE1, 0x45, 0xA5, 0xAB, 0xA3, 0x12, 0x7A, 0xF1, 0x97, 0xB5, 0xE7, 0x1F, 0xF3, 0xB8, 0x86, 0x73, 0xE9, 0x40, 0xA9, 0xF8, 0x2F, 0x21, 0x26, 0x3A, 0xCF, 0xB7, 0x56, 0xFF, 0x76, 0x97, 0xFD, 0x9B, 0x81, 0x45, 0xAD, 0x45, 0xB6, 0x45, 0xBB, 0xA5, 0x26, 0xD6, 0x03, 0x17, 0x00, 0x20, 0x0E, 0x00, 0x01, 0x00, 0x10, - 0x04, 0xA0, 0x01, 0x3A, 0xE8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x21, 0x20, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0xB0, 0x01, 0x03, 0xA2, 0x02, 0x00, 0x00, 0x00}; +const uint8_t xb1_descriptor[] = {0x04, 0xf0, 0x01, 0x3a, 0xa5, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x01, 0xcf, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x27, 0x00, 0x2d, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x05, 0x01, 0x04, 0x04, 0xa0, 0x01, 0xba, 0x00, 0x3a, 0x05, 0x06, 0x0a, 0x03, 0x19, 0x00, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x47, 0x48, 0x37, 0x1a, 0x00, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x47, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x04, 0xa0, 0x01, 0xba, 0x00, 0x74, 0x64, 0x27, 0x00, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x58, 0x62, 0x6f, 0x78, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x4e, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x04, 0xd9, 0xfd, 0x12, 0xfd, 0x73, 0x8e, 0xc7, 0x47, 0xa2, 0x31, 0x96, 0x26, 0x8c, 0x38, 0x00, 0x04, 0xa0, 0x01, 0x3a, 0xae, 0x01, 0x9a, 0x2c, 0x40, 0x2e, 0x08, 0xdf, 0x07, 0xe1, 0x45, 0xa5, 0xab, 0xa3, 0x12, 0x7a, 0xf1, 0x97, 0xb5, 0xe7, 0x1f, 0xf3, 0xb8, 0x86, 0x73, 0xe9, 0x40, 0xa9, 0xf8, 0x2f, 0x21, 0x26, 0x3a, 0xcf, 0xb7, 0x77, 0xce, 0x34, 0x7a, 0xe2, 0x7d, 0xc6, 0x45, 0x8c, 0xa4, 0x00, 0x42, 0xc0, 0x8b, 0xd9, 0x4a, 0x03, 0x17, 0x00, 0x20, 0x0e, 0x00, 0x01, 0x00, 0x10, 0x04, 0xb0, 0x01, 0x3a, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x21, 0x20, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xb0, 0x01, 0x03, 0xa2, 0x02, 0x00, 0x00, 0x00}; -const uint8_t xb1_descriptor_end[] = {0x04, 0xA0, 0x01, 0x00, 0xA5, 0x02}; +const uint8_t xb1_descriptor_end[] = {0x04, 0xa0, 0x01, 0x00, 0xa5, 0x02}; #elif DEVICE_TYPE == SKYLANDERS const uint8_t announce[] = {0x02, 0x20, 0x01, 0x1C, 0x5B, 0x9F, 0x9F, 0x96, 0x1B, 0x00, 0x00, 0x00, 0x30, 0x14, 0xAB, 0x09, 0x01, 0x00, 0x00, 0x00, 0x32, 0x02, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00}; const uint8_t xb1_descriptor[] = {0x04, 0xF0, 0x01, 0x3A, 0x96, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x6E, 0x00, 0x16, 0x00, 0x1B, 0x00, 0x1C, 0x00, 0x23, 0x00, 0x29, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x02, 0x03, 0x04, 0x06, 0x1F, 0x05, 0x01, 0x04, 0x05, 0x06, 0x1F, 0x01, 0x04, 0xA0, 0x01, 0xBA, 0x00, 0x3A, 0x21, 0x00, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x58, 0x62, 0x6F, 0x78, 0x2E, 0x53, 0x6B, 0x79, 0x6C, 0x61, 0x6E, 0x64, 0x65, 0x72, 0x73, 0x2E, 0x50, 0x6F, 0x72, 0x74, 0x61, 0x6C, 0x02, 0x00, 0xA2, 0x88, 0x77, 0x1F, 0x60, 0xB8, 0x40, 0x9B, 0x36, 0x26, 0xEC, 0x56, 0xC7, 0xC4, 0x52, 0x56, 0xFF, 0x76, 0x97, 0xFD, 0x9B, 0x04, 0xB0, 0x01, 0xA2, 0x00, 0x74, 0x81, 0x45, 0xAD, 0x45, 0xB6, 0x45, 0xBB, 0xA5, 0x26, 0xD6, 0x01, 0x17, 0x00, 0x21, 0x1E, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -85,4 +82,4 @@ const uint8_t xb1_descriptor[] = { const uint8_t xb1_descriptor_end[] = { 0x04, 0xa0, 0x03, 0x00, 0xdc, 0x01}; -#endif \ No newline at end of file +#endif diff --git a/src/shared/controllers/controllers.c b/src/shared/controllers/controllers.c index 8a759e248..8040adf95 100644 --- a/src/shared/controllers/controllers.c +++ b/src/shared/controllers/controllers.c @@ -8,21 +8,17 @@ bool seen_ps4 = false; bool seen_rpcs3 = false; bool descriptor_requested = false; Xbox_One_State_t xbox_one_state = Announce; -uint16_t xbox_360_vid = ARDWIINO_VID; -uint16_t xbox_360_pid = ARDWIINO_PID; Xbox_360_State_t xbox_360_state = Auth1; -uint8_t data_from_console_size = 0; -uint8_t data_from_controller_size = 0; -uint8_t data_from_console[64]; -uint8_t data_from_controller[64]; uint8_t keystroke_sequence_number; uint8_t report_sequence_number; uint8_t hid_sequence_number; uint8_t ps4_sequence_number; uint8_t portal_state = 0; bool seen_windows_xb1 = 0; +bool seen_os_descriptor_read = 0; +bool seen_og_xbox = false; bool seen_windows = false; -bool read_any_string = false; +bool read_any_device_string = false; bool read_device_desc = false; bool lastEuphoriaLed = false; bool proButtonsEnabled = false; diff --git a/src/shared/hid/hid.cpp b/src/shared/hid/hid.cpp index 01d55f0d6..cc3759d10 100644 --- a/src/shared/hid/hid.cpp +++ b/src/shared/hid/hid.cpp @@ -18,24 +18,25 @@ #include "usbhid.h" #include "util.h" #include "wii.h" +#include "Arduino.h" const PROGMEM char board[] = ARDWIINO_BOARD; const PROGMEM char f_cpu_descriptor_str[] = STR(F_CPU); uint8_t xbox_players[] = { - 0, // 0x00 All off - 0, // 0x01 All blinking - 1, // 0x02 1 flashes, then on - 2, // 0x03 2 flashes, then on - 3, // 0x04 3 flashes, then on - 4, // 0x05 4 flashes, then on - 1, // 0x06 1 on - 2, // 0x07 2 on - 3, // 0x08 3 on - 4, // 0x09 4 on - 0, // 0x0A Rotating (e.g. 1-2-4-3) - 0, // 0x0B Blinking* - 0, // 0x0C Slow blinking* - 0, // 0x0D Alternating (e.g. 1+4-2+3), then back to previous* + 0, // 0x00 All off + 0, // 0x01 All blinking + 1, // 0x02 1 flashes, then on + 2, // 0x03 2 flashes, then on + 3, // 0x04 3 flashes, then on + 4, // 0x05 4 flashes, then on + 1, // 0x06 1 on + 2, // 0x07 2 on + 3, // 0x08 3 on + 4, // 0x09 4 on + 0, // 0x0A Rotating (e.g. 1-2-4-3) + 0, // 0x0B Blinking* + 0, // 0x0C Slow blinking* + 0, // 0x0D Alternating (e.g. 1+4-2+3), then back to previous* }; static const int ps4_colors[4][3] = { @@ -46,10 +47,10 @@ static const int ps4_colors[4][3] = { }; uint8_t stage_kit_millis[] = { 0, - 75, // Fastest - 100, // Fast - 125, // Medium - 150, // Slow + 75, // Fastest + 100, // Fast + 125, // Medium + 150, // Slow }; uint8_t current_player = 0xFF; uint8_t strobe_delay = 0; @@ -234,129 +235,182 @@ ps3_output_report ps3_output_reports[8] = { }}; #endif -void handle_auth_led(void) { +void handle_auth_led(void) +{ authentication_successful(); HANDLE_AUTH_LED; } -void handle_player_leds(uint8_t player) { - if (player == current_player) return; - if (player == 0) { +void handle_player_leds(uint8_t player) +{ + if (player == current_player) + return; + if (player == 0) + { player = current_player; } - if (player == 0xFF) { + if (player == 0xFF) + { player = 1; } current_player = player; HANDLE_PLAYER_LED; #ifdef INPUT_USB_HOST USB_Device_Type_t type; - for (uint8_t i = 0; i < get_usb_host_device_count(); i++) { + for (uint8_t i = 0; i < get_usb_host_device_count(); i++) + { type = get_usb_host_device_type(i); - switch (type.console_type) { - case PS3: { - // Only actual ds3s support this - if (type.sub_type == GAMEPAD) { - ps3_output_report *report = &ps3_output_reports[i]; - report->leds_bitmap |= _BV(player); - transfer_with_usb_controller(type.dev_addr, (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_SET_REPORT, 0x0201, 0x00, sizeof(ps3_output_report), (uint8_t *)report, NULL); - // send_report_to_controller(type.dev_addr, (uint8_t *)report, sizeof(report)); - } - return; - } - case PS4: { - // Only actual ds4s support the lightbar - if (type.sub_type == GAMEPAD) { - ps4_output_report *report = &ps4_output_reports[i]; - report->lightbar_red = ps4_colors[player - 1][0]; - report->lightbar_green = ps4_colors[player - 1][1]; - report->lightbar_blue = ps4_colors[player - 1][2]; - transfer_with_usb_controller(type.dev_addr, (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_SET_REPORT, 0x0205, 0x00, sizeof(ps4_output_report), (uint8_t *)report, NULL); - } - return; + switch (type.console_type) + { + case PS3: + { + // Only actual ds3s support this + if (type.sub_type == GAMEPAD) + { + ps3_output_report *report = &ps3_output_reports[i]; + report->leds_bitmap |= _BV(player); + transfer_with_usb_controller(type, (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_SET_REPORT, 0x0201, sizeof(ps3_output_report), (uint8_t *)report, NULL); } - case XBOX360: { - XInputLEDReport_t report = { - rid : XBOX_LED_ID, - rsize : sizeof(XInputLEDReport_t), - led : (uint8_t)(player + LED_ONE - 1) - }; - send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&report, sizeof(report)); - return; + continue; + } + case PS4: + { + // Only actual ds4s support the lightbar + if (type.sub_type == GAMEPAD) + { + ps4_output_report *report = &ps4_output_reports[i]; + report->lightbar_red = ps4_colors[player - 1][0]; + report->lightbar_green = ps4_colors[player - 1][1]; + report->lightbar_blue = ps4_colors[player - 1][2]; + transfer_with_usb_controller(type, (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_SET_REPORT, 0x0205, sizeof(ps4_output_report), (uint8_t *)report, NULL); } - case XBOX360_W: { + continue; + } + case XBOX360: + { + XInputLEDReport_t report = { + rid : XBOX_LED_ID, + rsize : sizeof(XInputLEDReport_t), + led : (uint8_t)(player + LED_ONE - 1) + }; + send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&report, sizeof(report)); + continue; + } + case XBOX360_W: + { + // Don't send anything if the controller isnt connected + if (type.sub_type != UNKNOWN) + { uint8_t report[] = {0x00, 0x00, 0x08, (uint8_t)(0x40 | (player + LED_ONE - 1)), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; send_report_to_controller(type.dev_addr, type.instance, report, sizeof(report)); - return; } + continue; + } } } #endif } +void reset_player_leds(void) +{ + uint8_t player = 0; + current_player = 0xFF; + HANDLE_PLAYER_LED; +} // PS3 controllers and other controllers use different LED bitmasks #if DEVICE_TYPE == GAMEPAD -void handle_player_leds_ps3(uint8_t player_mask) { - if (player_mask == 2) { +void handle_player_leds_ps3(uint8_t player_mask) +{ + if (player_mask == 2) + { handle_player_leds(1); } - if (player_mask == 4) { + if (player_mask == 4) + { handle_player_leds(2); } - if (player_mask == 8) { + if (player_mask == 8) + { handle_player_leds(3); } - if (player_mask == 16) { + if (player_mask == 16) + { handle_player_leds(4); } - if (player_mask == 18) { + if (player_mask == 18) + { handle_player_leds(5); } - if (player_mask == 20) { + if (player_mask == 20) + { handle_player_leds(6); } - if (player_mask == 24) { + if (player_mask == 24) + { handle_player_leds(7); } } #else -void handle_player_leds_ps3(uint8_t player_mask) { - if (player_mask == 1) { +void handle_player_leds_ps3(uint8_t player_mask) +{ + if (player_mask == 1) + { handle_player_leds(1); } - if (player_mask == 2) { + if (player_mask == 2) + { handle_player_leds(2); } - if (player_mask == 4) { + if (player_mask == 4) + { handle_player_leds(3); } - if (player_mask == 8) { + if (player_mask == 8) + { handle_player_leds(4); } - if (player_mask == 9) { + if (player_mask == 9) + { handle_player_leds(5); } - if (player_mask == 10) { + if (player_mask == 10) + { handle_player_leds(6); } - if (player_mask == 12) { + if (player_mask == 12) + { handle_player_leds(7); } } #endif -void handle_lightbar_leds(uint8_t red, uint8_t green, uint8_t blue) { +void handle_lightbar_leds(uint8_t red, uint8_t green, uint8_t blue) +{ HANDLE_LIGHTBAR_LED; // We know the default lightbar colours that sony uses so we can extract a player number from that. - for (int i = 0; i < 4; i++) { - if (red == ps4_colors[i][0] && green == ps4_colors[i][1] && blue == ps4_colors[i][2]) { + for (int i = 0; i < 4; i++) + { + if (red == ps4_colors[i][0] && green == ps4_colors[i][1] && blue == ps4_colors[i][2]) + { handle_player_leds(i + 1); } } } +#if BLUETOOTH_RX +void send_player_leds_bt(void) +{ + if (current_player != 0xFF) + { + uint8_t player_leds_report[8] = {PS3_REPORT_ID, PS3_RUMBLE_ID, 0, (uint8_t)(1 << (current_player - 1)), 0, 0, 0, 0}; + bt_set_report(player_leds_report, sizeof(player_leds_report), 1, 1); + } +} +#endif -void handle_rumble(uint8_t rumble_left, uint8_t rumble_right) { +void handle_rumble(uint8_t rumble_left, uint8_t rumble_right) +{ // printf("Rumble: %d %d\r\n", rumble_left, rumble_right); HANDLE_RUMBLE; #ifdef HANDLE_LED_RUMBLE_OFF - if (rumble_left == 0x00 && rumble_right == 0xFF) { + if (rumble_left == 0x00 && rumble_right == 0xFF) + { last_strobe = 0; HANDLE_LED_RUMBLE_OFF; } @@ -364,64 +418,76 @@ void handle_rumble(uint8_t rumble_left, uint8_t rumble_right) { #if defined(INPUT_USB_HOST) && DEVICE_TYPE == GAMEPAD USB_Device_Type_t type; - for (uint8_t i = 0; i < get_usb_host_device_count(); i++) { + for (uint8_t i = 0; i < get_usb_host_device_count(); i++) + { type = get_usb_host_device_type(i); - if (type.sub_type != GAMEPAD && type.sub_type != XINPUT_WHEEL) continue; - switch (type.console_type) { - case PS3: { - ps3_output_report *report = &ps3_output_reports[i]; - report->rumble.left_motor_force = rumble_left; - report->rumble.right_motor_on = rumble_right != 0; - transfer_with_usb_controller(i, (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_SET_REPORT, 0x0201, 0x00, sizeof(ps3_output_report), (uint8_t *)report, NULL); - return; - } - case PS4: { - ps4_output_report *report = &ps4_output_reports[i]; - report->motor_left = rumble_left; - report->motor_right = rumble_right != 0; - send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)report, sizeof(ps4_output_report)); - return; - } - case OG_XBOX: { - uint8_t rumble_packet[] = {0x00, 0x06, 0x00, rumble_left, 0x00, rumble_right}; - send_report_to_controller(type.dev_addr, type.instance, rumble_packet, sizeof(rumble_packet)); - return; - } - case XBOX360: { - XInputRumbleReport_t report = { - rid : XBOX_RUMBLE_ID, - rsize : sizeof(XInputRumbleReport_t), - leftRumble : rumble_left, - rightRumble : rumble_right - }; - send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&report, sizeof(report)); - return; - } - case XBOX360_W: { - uint8_t rumble_packet[] = {0x00, 0x01, 0x0f, 0xc0, 0x00, rumble_left, rumble_right, 0x00, 0x00, 0x00, 0x00, 0x00}; - send_report_to_controller(type.dev_addr, type.instance, rumble_packet, sizeof(rumble_packet)); - return; - } - case XBOXONE: { - GipRumble_t report; - GipRumble_t *packet = &report; - GIP_HEADER(packet, GIP_CMD_RUMBLE, true, xone_sequences[i]++); - report.leftMotor = rumble_left; - report.rightMotor = rumble_right; - if (xone_sequences[i] == 0) { - xone_sequences[i] = 1; - } - send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&report, sizeof(report)); + if (type.sub_type != GAMEPAD && type.sub_type != XINPUT_WHEEL) + continue; + switch (type.console_type) + { + case PS3: + { + ps3_output_report *report = &ps3_output_reports[i]; + report->rumble.left_motor_force = rumble_left; + report->rumble.right_motor_on = rumble_right != 0; + transfer_with_usb_controller(type, (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_SET_REPORT, 0x0201, sizeof(ps3_output_report), (uint8_t *)report, NULL); + return; + } + case PS4: + { + ps4_output_report *report = &ps4_output_reports[i]; + report->motor_left = rumble_left; + report->motor_right = rumble_right != 0; + send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)report, sizeof(ps4_output_report)); + return; + } + case OG_XBOX: + { + uint8_t rumble_packet[] = {0x00, 0x06, 0x00, rumble_left, 0x00, rumble_right}; + send_report_to_controller(type.dev_addr, type.instance, rumble_packet, sizeof(rumble_packet)); + return; + } + case XBOX360: + { + XInputRumbleReport_t report = { + rid : XBOX_RUMBLE_ID, + rsize : sizeof(XInputRumbleReport_t), + leftRumble : rumble_left, + rightRumble : rumble_right + }; + send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&report, sizeof(report)); + return; + } + case XBOX360_W: + { + uint8_t rumble_packet[] = {0x00, 0x01, 0x0f, 0xc0, 0x00, rumble_left, rumble_right, 0x00, 0x00, 0x00, 0x00, 0x00}; + send_report_to_controller(type.dev_addr, type.instance, rumble_packet, sizeof(rumble_packet)); + return; + } + case XBOXONE: + { + GipRumble_t report; + GipRumble_t *packet = &report; + GIP_HEADER(packet, GIP_CMD_RUMBLE, true, xone_sequences[i]++); + report.leftMotor = rumble_left; + report.rightMotor = rumble_right; + if (xone_sequences[i] == 0) + { + xone_sequences[i] = 1; } + send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&report, sizeof(report)); + } } } #endif #if defined(INPUT_USB_HOST) && DEVICE_TYPE == STAGE_KIT USB_Device_Type_t type; // Only xinput has stage kit - for (uint8_t i = 0; i < get_usb_host_device_count(); i++) { + for (uint8_t i = 0; i < get_usb_host_device_count(); i++) + { type = get_usb_host_device_type(i); - if (type.sub_type != STAGE_KIT) continue; + if (type.sub_type != STAGE_KIT) + continue; XInputRumbleReport_t report = { rid : XBOX_RUMBLE_ID, rsize : sizeof(XInputRumbleReport_t), @@ -433,114 +499,124 @@ void handle_rumble(uint8_t rumble_left, uint8_t rumble_right) { } #endif #if DEVICE_TYPE == DJ_HERO_TURNTABLE - if (rumble_right == RUMBLE_SANTROLLER_EUPHORIA_LED) { + if (rumble_right == RUMBLE_SANTROLLER_EUPHORIA_LED) + { lastEuphoriaLed = rumble_left != 0; } #endif #if defined(INPUT_USB_HOST) && DEVICE_TYPE == DJ_HERO_TURNTABLE USB_Device_Type_t type; // Only ps3 and xinput have dj turntables - for (uint8_t i = 0; i < get_usb_host_device_count(); i++) { + for (uint8_t i = 0; i < get_usb_host_device_count(); i++) + { type = get_usb_host_device_type(i); - if (type.sub_type != DJ_HERO_TURNTABLE) continue; - switch (type.console_type) { - case XBOX360: { - XInputRumbleReport_t report = { - rid : XBOX_RUMBLE_ID, - rsize : sizeof(XInputRumbleReport_t), - leftRumble : rumble_left, - rightRumble : rumble_right - }; - send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&report, sizeof(report)); - return; - } - case PS3: { - ps3_turntable_output_report_t report = { - outputType : DJ_LED_ID, - unknown1 : 0x01, - enable : rumble_left != 0, - padding : {0} - }; - transfer_with_usb_controller(i, (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_SET_REPORT, 0x0200, 0x00, sizeof(report), (uint8_t *)&report, NULL); - return; - } + if (type.sub_type != DJ_HERO_TURNTABLE) + continue; + switch (type.console_type) + { + case XBOX360: + { + XInputRumbleReport_t report = { + rid : XBOX_RUMBLE_ID, + rsize : sizeof(XInputRumbleReport_t), + leftRumble : rumble_left, + rightRumble : rumble_right + }; + send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&report, sizeof(report)); + return; + } + case PS3: + { + ps3_turntable_output_report_t report = { + outputType : DJ_LED_ID, + unknown1 : 0x01, + enable : rumble_left != 0, + padding : {0} + }; + transfer_with_usb_controller(type, (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_SET_REPORT, 0x0200, sizeof(report), (uint8_t *)&report, NULL); + return; + } } } #endif } -void handle_rumble(PCStageKitOutputWithoutReportId_Data_t *report) { +void handle_rumble(PCStageKitOutputWithoutReportId_Data_t *report) +{ HANDLE_RUMBLE_EXPANDED; } -void handle_keyboard_leds(uint8_t leds) { +void handle_keyboard_leds(uint8_t leds) +{ HANDLE_KEYBOARD_LED; } #if BLUETOOTH_RX -void handle_bt_rumble(uint8_t rumble_left, uint8_t rumble_right) { - switch (rumble_right) { - case RUMBLE_STAGEKIT_FOG_ON: - stage_kit_report.report.stageKitFog = true; - break; - case RUMBLE_STAGEKIT_FOG_OFF: - stage_kit_report.report.stageKitFog = false; - break; - case RUMBLE_STAGEKIT_SLOW_STROBE: - stage_kit_report.report.stageKitStrobe = 1; - break; - case RUMBLE_STAGEKIT_MEDIUM_STROBE: - stage_kit_report.report.stageKitStrobe = 2; - break; - case RUMBLE_STAGEKIT_FAST_STROBE: - stage_kit_report.report.stageKitStrobe = 3; - break; - case RUMBLE_STAGEKIT_FASTEST_STROBE: - stage_kit_report.report.stageKitStrobe = 4; - break; - case RUMBLE_STAGEKIT_NO_STROBE: - stage_kit_report.report.stageKitStrobe = 0; - break; - case RUMBLE_STAGEKIT_ALLOFF: - stage_kit_report.report.stageKitFog = false; - stage_kit_report.report.stageKitStrobe = 0; - stage_kit_report.report.stageKitBlue = 0; - stage_kit_report.report.stageKitGreen = 0; - stage_kit_report.report.stageKitYellow = 0; - stage_kit_report.report.stageKitRed = 0; - break; - case RUMBLE_STAGEKIT_BLUE: - stage_kit_report.report.stageKitBlue = rumble_left; - break; - case RUMBLE_STAGEKIT_GREEN: - stage_kit_report.report.stageKitGreen = rumble_left; - break; - case RUMBLE_STAGEKIT_YELLOW: - stage_kit_report.report.stageKitYellow = rumble_left; - break; - case RUMBLE_STAGEKIT_RED: - stage_kit_report.report.stageKitRed = rumble_left; - break; - case RUMBLE_SANTROLLER_NOTE_MISS: - stage_kit_report.report.noteMiss = rumble_left; - break; - case RUMBLE_SANTROLLER_MULTIPLIER: - stage_kit_report.report.multiplier = rumble_left; - break; - case RUMBLE_SANTROLLER_SOLO: - stage_kit_report.report.soloActive = rumble_left; - break; - case RUMBLE_SANTROLLER_STAR_POWER_ACTIVE: - stage_kit_report.report.starPowerActive = rumble_left; - break; - case RUMBLE_SANTROLLER_STAR_POWER_FILL: - stage_kit_report.report.starPowerState = rumble_left; - break; - case RUMBLE_SANTROLLER_NOTE_HIT: - stage_kit_report.report.noteHitRaw = rumble_left; - break; +void handle_bt_rumble(uint8_t rumble_left, uint8_t rumble_right) +{ + switch (rumble_right) + { + case RUMBLE_STAGEKIT_FOG_ON: + stage_kit_report.report.stageKitFog = true; + break; + case RUMBLE_STAGEKIT_FOG_OFF: + stage_kit_report.report.stageKitFog = false; + break; + case RUMBLE_STAGEKIT_SLOW_STROBE: + stage_kit_report.report.stageKitStrobe = 1; + break; + case RUMBLE_STAGEKIT_MEDIUM_STROBE: + stage_kit_report.report.stageKitStrobe = 2; + break; + case RUMBLE_STAGEKIT_FAST_STROBE: + stage_kit_report.report.stageKitStrobe = 3; + break; + case RUMBLE_STAGEKIT_FASTEST_STROBE: + stage_kit_report.report.stageKitStrobe = 4; + break; + case RUMBLE_STAGEKIT_NO_STROBE: + stage_kit_report.report.stageKitStrobe = 0; + break; + case RUMBLE_STAGEKIT_ALLOFF: + stage_kit_report.report.stageKitFog = false; + stage_kit_report.report.stageKitStrobe = 0; + stage_kit_report.report.stageKitBlue = 0; + stage_kit_report.report.stageKitGreen = 0; + stage_kit_report.report.stageKitYellow = 0; + stage_kit_report.report.stageKitRed = 0; + break; + case RUMBLE_STAGEKIT_BLUE: + stage_kit_report.report.stageKitBlue = rumble_left; + break; + case RUMBLE_STAGEKIT_GREEN: + stage_kit_report.report.stageKitGreen = rumble_left; + break; + case RUMBLE_STAGEKIT_YELLOW: + stage_kit_report.report.stageKitYellow = rumble_left; + break; + case RUMBLE_STAGEKIT_RED: + stage_kit_report.report.stageKitRed = rumble_left; + break; + case RUMBLE_SANTROLLER_NOTE_MISS: + stage_kit_report.report.noteMiss = rumble_left; + break; + case RUMBLE_SANTROLLER_MULTIPLIER: + stage_kit_report.report.multiplier = rumble_left; + break; + case RUMBLE_SANTROLLER_SOLO: + stage_kit_report.report.soloActive = rumble_left; + break; + case RUMBLE_SANTROLLER_STAR_POWER_ACTIVE: + stage_kit_report.report.starPowerActive = rumble_left; + break; + case RUMBLE_SANTROLLER_STAR_POWER_FILL: + stage_kit_report.report.starPowerState = rumble_left; + break; + case RUMBLE_SANTROLLER_NOTE_HIT: + stage_kit_report.report.noteHitRaw = rumble_left; + break; #if DEVICE_TYPE == DJ_HERO_TURNTABLE - case RUMBLE_SANTROLLER_EUPHORIA_LED: - stage_kit_report.report.euphoriaBrightness = rumble_left; - break; + case RUMBLE_SANTROLLER_EUPHORIA_LED: + stage_kit_report.report.euphoriaBrightness = rumble_left; + break; #endif } stage_kit_report.reportId = PS3_RUMBLE_ID; @@ -549,7 +625,8 @@ void handle_bt_rumble(uint8_t rumble_left, uint8_t rumble_right) { } #endif -void hid_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_t report_id) { +void hid_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_t report_id) +{ // for (int i = 0; i < len; i++) { // printf("%02x, ", data[i]); // } @@ -559,42 +636,62 @@ void hid_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_ // portal_state = 1; // } // } + if (consoleType == ARCADE) + { + if (data[0] == 0x03) + { + // packet sends 0 for left and 1 for right, hid report uses 1 for left and 2 for right + setArcadeSide(data[1] + 1); + } + return; + } #if DEVICE_TYPE_IS_KEYBOARD handle_keyboard_leds(data[0]); #endif uint8_t id = data[0]; #if defined(INPUT_USB_HOST) - for (uint8_t i = 0; i < get_usb_host_device_count(); i++) { + for (uint8_t i = 0; i < get_usb_host_device_count(); i++) + { USB_Device_Type_t type = get_usb_host_device_type(i); - if (type.console_type != SANTROLLER) continue; + if (type.console_type != SANTROLLER) + continue; // Convert xinput payloads to their hid counterparts and send - if ((consoleType == XBOX360 || consoleType == WINDOWS) && report_id != BLUETOOTH_REPORT) { + if ((consoleType == XBOX360 || consoleType == WINDOWS) && report_id != BLUETOOTH_REPORT) + { uint8_t data_hid[8] = {0}; data_hid[0] = PS3_REPORT_ID; - if (id == XBOX_LED_ID) { + if (id == XBOX_LED_ID) + { uint8_t led = data[2]; uint8_t player = xbox_players[led]; - if (player) { + if (player) + { data_hid[1] = PS3_LED_ID; data_hid[3] = 1 << player; send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&data_hid, sizeof(data_hid)); } - - } else if (id == XBOX_RUMBLE_ID) { + } + else if (id == XBOX_RUMBLE_ID) + { data_hid[1] = SANTROLLER_LED_ID; data_hid[2] = data[3]; data_hid[3] = data[4]; send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&data_hid, sizeof(data_hid)); } - } else if ((consoleType == XBOXONE) && report_id != BLUETOOTH_REPORT) { - if (xbox_one_state == Ready) { + } + else if ((consoleType == XBOXONE) && report_id != BLUETOOTH_REPORT) + { + if (xbox_one_state == Ready) + { uint8_t data_hid[8] = {0}; data_hid[0] = PS3_REPORT_ID; // Live guitar is a bit special, so handle it here #if DEVICE_TYPE == LIVE_GUITAR - if (id == GHL_HID_OUTPUT) { + if (id == GHL_HID_OUTPUT) + { uint8_t sub_id = data[1]; - if (sub_id == PS3_RUMBLE_ID) { + if (sub_id == PS3_RUMBLE_ID) + { uint8_t player = (data[3] & 0x0F); data_hid[1] = PS3_RUMBLE_ID; data_hid[3] = 1 << player; @@ -602,7 +699,8 @@ void hid_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_ } } #endif - if (id == GIP_CMD_RUMBLE) { + if (id == GIP_CMD_RUMBLE) + { GipRumble_t *rumble = (GipRumble_t *)data; data_hid[1] = SANTROLLER_LED_ID; data_hid[2] = rumble->leftMotor; @@ -610,7 +708,9 @@ void hid_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_ send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&data_hid, sizeof(data_hid)); } } - } else { + } + else + { // Already a hid payload, send it as is send_report_to_controller(type.dev_addr, type.instance, data, len); } @@ -618,20 +718,22 @@ void hid_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_ #endif #if BLUETOOTH_RX // BT uses HID, so convert XInput based reports to HID before sending them over BT - if (consoleType == XBOX360 || consoleType == WINDOWS) { + if (consoleType == XBOX360 || consoleType == WINDOWS) + { uint8_t data_hid[8] = {0}; data_hid[0] = PS3_REPORT_ID; - if (id == XBOX_LED_ID) { + if (id == XBOX_LED_ID) + { uint8_t led = data[2]; uint8_t player = xbox_players[led]; - if (player) { + if (player) + { handle_player_leds(player); - data_hid[1] = PS3_RUMBLE_ID; - data_hid[3] = 1 << player; - bt_set_report(data_hid, 8, reportType, report_id); + send_player_leds_bt(); } - - } else if (id == XBOX_RUMBLE_ID) { + } + else if (id == XBOX_RUMBLE_ID) + { #if DEVICE_TYPE == GAMEPAD data_hid[1] = SANTROLLER_LED_ID; data_hid[2] = data[3]; @@ -641,448 +743,605 @@ void hid_set_report(const uint8_t *data, uint8_t len, uint8_t reportType, uint8_ handle_bt_rumble(data[3], data[4]); #endif } - } else { + } + else + { #if DEVICE_TYPE == GAMEPAD bt_set_report(data, len, reportType, report_id); #else // Convert rumble based reports to combined reports - if (id == SANTROLLER_LED_ID) { + if (id == SANTROLLER_LED_ID) + { handle_bt_rumble(data[1], data[2]); - } else if (id == PS3_REPORT_ID && data[1] == SANTROLLER_LED_ID) { + } + else if (id == PS3_REPORT_ID && data[1] == SANTROLLER_LED_ID) + { handle_bt_rumble(data[2], data[3]); // Pass combined reports directly over bt - } else if (id == SANTROLLER_LED_EXPANDED_ID || (id == PS3_REPORT_ID && data[1] == SANTROLLER_LED_EXPANDED_ID)) { + } + else if (id == SANTROLLER_LED_EXPANDED_ID || (id == PS3_REPORT_ID && data[1] == SANTROLLER_LED_EXPANDED_ID)) + { + bt_set_report(data, len, reportType, report_id); + } + else if (id == PS3_REPORT_ID && data[1] == 0x08) // PS3s apparently send an 8 byte Player ID report, and that length is in data[1] + { bt_set_report(data, len, reportType, report_id); } #endif } #endif -#ifdef INPUT_USB_HOST // Handle Xbox 360 LEDs and rumble // Handle XBOX One Auth - if ((consoleType == XBOXONE) && report_id != BLUETOOTH_REPORT) { - if (xbox_one_state == WaitingDesc1) { + if ((consoleType == XBOXONE) && report_id != BLUETOOTH_REPORT) + { + if (xbox_one_state == WaitingDesc1) + { xbox_one_state = IdentDesc1; - } else if (xbox_one_state == WaitingDesc) { + } + else if (xbox_one_state == WaitingDesc) + { xbox_one_state = IdentDesc; - } else if (xbox_one_state == WaitingDescEnd) { + } + else if (xbox_one_state == WaitingDescEnd) + { xbox_one_state = IdentDescEnd; - } else if (xbox_one_state == Auth) { - delay(1); - if (data[0] == GIP_AUTHENTICATION && len == 6 && data[3] == 2 && data[4] == 1 && data[5] == 0) { + } + else if (xbox_one_state == Auth) + { + if (data[0] == GIP_AUTHENTICATION && len == 6 && data[3] == 2 && data[4] == 1 && data[5] == 0) + { handle_auth_led(); printf("Ready!\r\n"); xbox_one_state = Ready; - data_from_console_size = len; - memcpy(data_from_console, data, len); - } else if (data[0] != GIP_POWER_MODE_DEVICE_CONFIG && data[0] != 2 && data[0] != 4) { - data_from_console_size = len; - memcpy(data_from_console, data, len); + +#if USB_HOST_STACK + USB_Device_Type_t type = get_device_address_for(XBOXONE); + while (!send_report_to_controller(type.dev_addr, type.instance, data, len)) + { + tuh_task(); + } +#endif } - } else if (xbox_one_state == Ready) { + else if (data[0] != GIP_POWER_MODE_DEVICE_CONFIG && data[0] != 2 && data[0] != 4) + { +#if USB_HOST_STACK + USB_Device_Type_t type = get_device_address_for(XBOXONE); + while (!send_report_to_controller(type.dev_addr, type.instance, data, len)) + { + tuh_task(); + } +#endif + } + } + else if (xbox_one_state == Ready) + { // Live guitar is a bit special, so handle it here #if DEVICE_TYPE == LIVE_GUITAR - if (id == GHL_HID_OUTPUT) { + if (id == GHL_HID_OUTPUT) + { uint8_t sub_id = data[1]; - if (sub_id == PS3_RUMBLE_ID) { + if (sub_id == PS3_RUMBLE_ID) + { uint8_t player = (data[3] & 0x0F); handle_player_leds(player + 1); } } #endif - if (id == GIP_CMD_RUMBLE) { + if (id == GIP_CMD_RUMBLE) + { GipRumble_t *rumble = (GipRumble_t *)data; handle_rumble(rumble->leftMotor, rumble->rightMotor); } } - } else -#endif + } + else // Bt reports are ALWAYS hid even if USB is in xinput mode - if ((consoleType == XBOX360 || consoleType == WINDOWS) && report_id != BLUETOOTH_REPORT) { - if (id == XBOX_LED_ID) { + if ((consoleType == XBOX360 || consoleType == WINDOWS) && report_id != BLUETOOTH_REPORT) + { + if (id == XBOX_LED_ID) + { uint8_t led = data[2]; uint8_t player = xbox_players[led]; - if (player) { + if (player) + { handle_player_leds(player); } - - } else if (id == XBOX_RUMBLE_ID) { + } + else if (id == XBOX_RUMBLE_ID) + { uint8_t rumble_left = data[3]; uint8_t rumble_right = data[4]; // Turntable commands will conflict as the actual game sends rumble out on both motors at the same time // To solve this problem, we stay in a turntable compatibility mode until we receive a valid santroller command #if DEVICE_TYPE == DJ_HERO_TURNTABLE - if ((rumble_right >= RUMBLE_SANTROLLER_STAR_POWER_FILL && rumble_right <= RUMBLE_SANTROLLER_NOTE_MISS) || rumble_right == RUMBLE_SANTROLLER_NOTE_HIT) { - if (rumble_left != rumble_right) { + if ((rumble_right >= RUMBLE_SANTROLLER_STAR_POWER_FILL && rumble_right <= RUMBLE_SANTROLLER_NOTE_MISS) || rumble_right == RUMBLE_SANTROLLER_NOTE_HIT) + { + if (rumble_left != rumble_right) + { received_valid_command = true; } } // Turntable led emulation mode - if (!received_valid_command && rumble_left == rumble_right) { + if (!received_valid_command && rumble_left == rumble_right) + { rumble_right = RUMBLE_SANTROLLER_EUPHORIA_LED; } #endif handle_rumble(rumble_left, rumble_right); } - } else { - if (id == PS4_LED_RUMBLE_ID) { + } + else + { + if (id == PS4_LED_RUMBLE_ID) + { ps4_output_report *report = (ps4_output_report *)data; handle_lightbar_leds(report->lightbar_red, report->lightbar_green, report->lightbar_blue); handle_rumble(report->motor_left, report->motor_right); #if defined(INPUT_USB_HOST) && DEVICE_TYPE == GAMEPAD USB_Device_Type_t type; - for (uint8_t i = 0; i < get_usb_host_device_count(); i++) { + for (uint8_t i = 0; i < get_usb_host_device_count(); i++) + { type = get_usb_host_device_type(i); - if (type.sub_type != GAMEPAD || type.console_type != PS4) continue; + if (type.sub_type != GAMEPAD || type.console_type != PS4) + continue; send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)report, sizeof(ps4_output_report)); return; } #endif } #if DEVICE_TYPE_IS_INSTRUMENT - else if (id == PS3_REPORT_ID && data[1] == SANTROLLER_LED_ID) { + else if (id == PS3_REPORT_ID && data[1] == SANTROLLER_LED_ID) + { handle_rumble(data[2], data[3]); - } else if (id == PS3_REPORT_ID && data[1] == SANTROLLER_LED_EXPANDED_ID) { + } + else if (id == PS3_REPORT_ID && data[1] == SANTROLLER_LED_EXPANDED_ID) + { PCStageKitOutput_Data_t *output = (PCStageKitOutput_Data_t *)data; handle_rumble(&output->report); - } else if (id == PS3_REPORT_ID && data[1] == PS3_RUMBLE_ID) { + } + else if (id == PS3_REPORT_ID && data[1] == PS3_RUMBLE_ID) + { uint8_t player = data[3]; handle_player_leds_ps3(player); - } else if (id == PS3_RUMBLE_ID) { + } + else if (id == PS3_RUMBLE_ID) + { uint8_t player = data[2]; handle_player_leds_ps3(player); - } else if (id == SANTROLLER_LED_ID) { + } + else if (id == SANTROLLER_LED_ID) + { handle_rumble(data[1], data[2]); - } else if (id == SANTROLLER_LED_EXPANDED_ID) { + } + else if (id == SANTROLLER_LED_EXPANDED_ID) + { PCStageKitOutputWithoutReportId_Data_t *output = (PCStageKitOutputWithoutReportId_Data_t *)data; handle_rumble(output); } #if DEVICE_TYPE == DJ_HERO_TURNTABLE - else if (id == DJ_LED_ID) { + else if (id == DJ_LED_ID) + { uint8_t euphoria_on = data[2] * 0xFF; // Use the santroller euphoria rumble command so that rumble is correctly mapped handle_rumble(euphoria_on, RUMBLE_SANTROLLER_EUPHORIA_LED); } #endif #else - else if (id == PS3_LED_ID) { - handle_player_leds_ps3(data[9]); - handle_rumble(data[0x04], data[0x02] ? 0xff : 0); - } else if (id == PS3_RUMBLE_ID) { - handle_rumble(data[0x05], data[0x03] ? 0xff : 0); - } + else if (id == PS3_LED_ID) + { + handle_player_leds_ps3(data[9]); + handle_rumble(data[0x04], data[0x02] ? 0xff : 0); + } + else if (id == PS3_RUMBLE_ID) + { + handle_rumble(data[0x05], data[0x03] ? 0xff : 0); + } #endif } } long millis_since_command = 0; -uint8_t handle_serial_command(uint8_t request, uint16_t wValue, uint8_t *response_buffer, bool *success) { - switch (request) { - case COMMAND_READ_CONFIG: { - if (wValue > CONFIGURATION_LEN) { - return 0; - } - uint16_t size = CONFIGURATION_LEN - wValue; - if (size > 64) size = 64; - memcpy_P(response_buffer, config + wValue, size); - return size; +uint16_t handle_serial_command(uint8_t request, uint16_t wValue, uint8_t *response_buffer, bool *success) +{ + switch (request) + { + case COMMAND_READ_CONFIG: + { + if (wValue > CONFIGURATION_LEN) + { + return 0; } - case COMMAND_READ_SERIAL: - read_serial(response_buffer, 20); - return 20; - case COMMAND_READ_BOARD: - memcpy_P(response_buffer, board, sizeof(board)); - return sizeof(board); - case COMMAND_READ_F_CPU: - memcpy_P(response_buffer, f_cpu_descriptor_str, sizeof(f_cpu_descriptor_str)); - return sizeof(f_cpu_descriptor_str); + uint16_t size = CONFIGURATION_LEN - wValue; + if (size > 64) + size = 64; + memcpy_P(response_buffer, config + wValue, size); + return size; + } + case COMMAND_READ_SERIAL: + read_serial(response_buffer, 20); + return 20; + case COMMAND_READ_BOARD: + memcpy_P(response_buffer, board, sizeof(board)); + return sizeof(board); + case COMMAND_READ_F_CPU: + memcpy_P(response_buffer, f_cpu_descriptor_str, sizeof(f_cpu_descriptor_str)); + return sizeof(f_cpu_descriptor_str); - case COMMAND_GET_EXTENSION_WII: - if (!lastWiiWasSuccessful) { - return 0; - } - memcpy(response_buffer, &wiiControllerType, sizeof(wiiControllerType)); - return sizeof(wiiControllerType); - case COMMAND_GET_EXTENSION_PS2: - if (!lastPS2WasSuccessful) { - return 0; - } - memcpy(response_buffer, &ps2ControllerType, sizeof(ps2ControllerType)); - return sizeof(ps2ControllerType); - case COMMAND_READ_WII: - if (!lastWiiWasSuccessful) { - return 0; - } - memcpy(response_buffer, &lastSuccessfulWiiPacket, wiiBytes); - return wiiBytes; - case COMMAND_READ_PS2: - if (!lastPS2WasSuccessful) { - return 0; - } - memcpy(response_buffer, &lastSuccessfulPS2Packet, sizeof(lastSuccessfulPS2Packet)); - return sizeof(lastSuccessfulPS2Packet); - case COMMAND_READ_DJ_LEFT: - if (!lastTurntableWasSuccessfulLeft) { - return 0; - } - memcpy(response_buffer, &lastSuccessfulTurntablePacketLeft, sizeof(lastSuccessfulTurntablePacketLeft)); - return sizeof(lastSuccessfulTurntablePacketLeft); - case COMMAND_READ_DJ_RIGHT: - if (!lastTurntableWasSuccessfulRight) { - return 0; - } - memcpy(response_buffer, &lastSuccessfulTurntablePacketRight, sizeof(lastSuccessfulTurntablePacketRight)); - return sizeof(lastSuccessfulTurntablePacketRight); - case COMMAND_READ_GH5: - if (!lastGH5WasSuccessful) { - return 0; - } - memcpy(response_buffer, &lastSuccessfulGH5Packet, sizeof(lastSuccessfulGH5Packet)); - return sizeof(lastSuccessfulGH5Packet); - case COMMAND_READ_CLONE: - if (!lastCloneWasSuccessful) { - return 0; - } - memcpy(response_buffer, &lastSuccessfulClonePacket, sizeof(lastSuccessfulClonePacket)); - return sizeof(lastSuccessfulClonePacket); -#ifdef INPUT_WT_NECK - case COMMAND_READ_GHWT: { - volatile uint8_t *data = (volatile uint8_t *)lastWt; - for (int i = 0; i < sizeof(lastWt); i++) { - response_buffer[i] = data[i]; - } - return sizeof(lastWt); - } -#endif - case COMMAND_READ_ANALOG: { - uint8_t pin = wValue & 0xff; - uint8_t mask = (wValue >> 8); - uint16_t response = adc_read(pin, mask); - memcpy(response_buffer, &response, sizeof(response)); - return sizeof(response); + case COMMAND_GET_EXTENSION_WII: + if (!lastWiiWasSuccessful) + { + return 0; } - case COMMAND_READ_ACCEL: { - memcpy(response_buffer, &filtered, sizeof(filtered)); - memcpy(response_buffer + sizeof(filtered), &accel_adc, sizeof(accel_adc)); - return sizeof(filtered) + sizeof(accel_adc); + memcpy(response_buffer, &wiiControllerType, sizeof(wiiControllerType)); + return sizeof(wiiControllerType); + case COMMAND_GET_EXTENSION_PS2: + if (!lastPS2WasSuccessful) + { + return 0; } - case COMMAND_ACCEL_VALID: { - response_buffer[0] = accel_found; - return 1; + memcpy(response_buffer, &ps2ControllerType, sizeof(ps2ControllerType)); + return sizeof(ps2ControllerType); + case COMMAND_READ_WII: + if (!lastWiiWasSuccessful) + { + return 0; } - case COMMAND_SET_ACCEL_FILTER: { - memcpy(¤tLowPassAlpha, response_buffer, sizeof(currentLowPassAlpha)); + memcpy(response_buffer, &lastSuccessfulWiiPacket, wiiBytes); + return wiiBytes; + case COMMAND_READ_PS2: + if (!lastPS2WasSuccessful) + { return 0; } - case COMMAND_READ_DIGITAL: { - uint8_t port = wValue & 0xff; - uint8_t mask = (wValue >> 8); - uint8_t response = digital_read(port, mask); - memcpy(response_buffer, &response, sizeof(response)); - return sizeof(response); + memcpy(response_buffer, &lastSuccessfulPS2Packet, sizeof(lastSuccessfulPS2Packet)); + return sizeof(lastSuccessfulPS2Packet); + case COMMAND_READ_DJ_LEFT: + if (!lastTurntableWasSuccessfulLeft) + { + return 0; } - case COMMAND_WRITE_ANALOG: { - uint8_t port = response_buffer[0]; - uint8_t value = response_buffer[1]; - analogWrite(port, value); + memcpy(response_buffer, &lastSuccessfulTurntablePacketLeft, sizeof(lastSuccessfulTurntablePacketLeft)); + return sizeof(lastSuccessfulTurntablePacketLeft); + case COMMAND_READ_DJ_RIGHT: + if (!lastTurntableWasSuccessfulRight) + { return 0; } - case COMMAND_WRITE_DIGITAL: { - uint8_t port = response_buffer[0]; - uint8_t mask = response_buffer[1]; - uint8_t activeMask = response_buffer[2]; - digital_write(port, mask, activeMask); + memcpy(response_buffer, &lastSuccessfulTurntablePacketRight, sizeof(lastSuccessfulTurntablePacketRight)); + return sizeof(lastSuccessfulTurntablePacketRight); + case COMMAND_READ_GH5: + if (!lastGH5WasSuccessful) + { return 0; } - case COMMAND_LED_BRIGHTNESS: { - brightness = response_buffer[0]; + memcpy(response_buffer, &lastSuccessfulGH5Packet, sizeof(lastSuccessfulGH5Packet)); + return sizeof(lastSuccessfulGH5Packet); + case COMMAND_READ_CLONE: + if (!lastCloneWasSuccessful) + { return 0; } - case COMMAND_DISABLE_MULTIPLEXER: { - disable_multiplexer = response_buffer[0]; + memcpy(response_buffer, &lastSuccessfulClonePacket, sizeof(lastSuccessfulClonePacket)); + return sizeof(lastSuccessfulClonePacket); + case COMMAND_READ_CRKD: + if (!lastCrkdWasSuccessful) + { + return 0; } - case COMMAND_READ_MIDI: { - memcpy(response_buffer, &midiData.midiVelocities, (sizeof(Midi_Data_t) - offsetof(Midi_Data_t, midiVelocities))); - return (sizeof(Midi_Data_t) - offsetof(Midi_Data_t, midiVelocities)); + memcpy(response_buffer, &lastCrkd, sizeof(lastCrkd)); + return sizeof(lastCrkd); +#ifdef INPUT_WT_NECK + case COMMAND_READ_GHWT: + { + volatile uint8_t *data = (volatile uint8_t *)lastWt; + for (int i = 0; i < sizeof(lastWt); i++) + { + response_buffer[i] = data[i]; } + return sizeof(lastWt); + } +#endif + case COMMAND_READ_ANALOG: + { + uint8_t pin = wValue & 0xff; + uint8_t mask = (wValue >> 8); + uint16_t response = adc_read(pin, mask); + memcpy(response_buffer, &response, sizeof(response)); + return sizeof(response); + } + case COMMAND_READ_ACCEL: + { + memcpy(response_buffer, &filtered, sizeof(filtered)); + memcpy(response_buffer + sizeof(filtered), &accel_adc, sizeof(accel_adc)); + return sizeof(filtered) + sizeof(accel_adc); + } + case COMMAND_ACCEL_VALID: + { + response_buffer[0] = accel_found; + return 1; + } + case COMMAND_SET_ACCEL_FILTER: + { + memcpy(¤tLowPassAlpha, response_buffer, sizeof(currentLowPassAlpha)); + return 0; + } + case COMMAND_READ_DIGITAL: + { + uint8_t port = wValue & 0xff; + uint8_t mask = (wValue >> 8); + uint8_t response = digital_read(port, mask); + memcpy(response_buffer, &response, sizeof(response)); + return sizeof(response); + } + case COMMAND_WRITE_ANALOG: + { + uint8_t port = response_buffer[0]; + uint8_t value = response_buffer[1]; + analogWrite(port, value); + return 0; + } + case COMMAND_WRITE_DIGITAL: + { + uint8_t port = response_buffer[0]; + uint8_t mask = response_buffer[1]; + uint8_t activeMask = response_buffer[2]; + digital_write(port, mask, activeMask); + return 0; + } + case COMMAND_LED_BRIGHTNESS: + { + brightness = response_buffer[0]; + return 0; + } + case COMMAND_DISABLE_MULTIPLEXER: + { + disable_multiplexer = response_buffer[0]; + return 0; + } + + case COMMAND_READ_MATRIX: + { + uint8_t outPin = wValue & 0xff; + uint8_t pin = (wValue >> 8); + response_buffer[0] = matrix_read(pin, outPin); + return 1; + } + case COMMAND_READ_MIDI: + { + memcpy(response_buffer, &midiData.midiVelocities, (sizeof(Midi_Data_t) - offsetof(Midi_Data_t, midiVelocities))); + return (sizeof(Midi_Data_t) - offsetof(Midi_Data_t, midiVelocities)); + } #ifdef WT_DRUM_SPI_PORT - case COMMAND_WT_DRUM_VALID: - response_buffer[0] = wt_drum_found; - return 1; + case COMMAND_WT_DRUM_VALID: + response_buffer[0] = wt_drum_found; + return 1; +#endif +#ifdef MUSTANG_NECK_SPI_PORT + case COMMAND_MUSTANG_NECK_VALID: + response_buffer[0] = mustang_neck_found; + return 1; +#endif +#ifdef BH_DRUM_TWI_PORT + case COMMAND_BH_DRUM_VALID: + response_buffer[0] = bh_drum_found; + return 1; #endif #ifdef MAX1704X_TWI_PORT - case COMMAND_READ_MAX170X_VALID: - response_buffer[0] = max170x_init; - return 1; - case COMMAND_READ_MAX170X: - memcpy(response_buffer, &lastBattery, sizeof(lastBattery)); - return sizeof(lastBattery); + case COMMAND_READ_MAX170X_VALID: + response_buffer[0] = max170x_init; + return 1; + case COMMAND_READ_MAX170X: + memcpy(response_buffer, &lastBattery, sizeof(lastBattery)); + return sizeof(lastBattery); #endif #ifdef MPR121_TWI_PORT - case COMMAND_READ_MPR121_VALID: - response_buffer[0] = mpr121_init; - return 1; - case COMMAND_READ_MPR121: - memcpy(response_buffer, &lastMpr121, sizeof(lastMpr121)); - return sizeof(lastMpr121); + case COMMAND_READ_MPR121_VALID: + response_buffer[0] = mpr121_init; + return 1; + case COMMAND_READ_MPR121: + memcpy(response_buffer, &lastMpr121, sizeof(lastMpr121)); + return sizeof(lastMpr121); #endif #ifdef SLAVE_TWI_PORT #ifdef INPUT_WT_SLAVE_NECK - case COMMAND_READ_PERIPHERAL_GHWT: - return slaveReadWtRaw(response_buffer); + case COMMAND_READ_PERIPHERAL_GHWT: + return slaveReadWtRaw(response_buffer); #endif - case COMMAND_READ_PERIPHERAL_VALID: - response_buffer[0] = slave_initted; - return 1; - case COMMAND_READ_PERIPHERAL_DIGITAL: { - uint8_t port = wValue & 0xff; - uint8_t mask = (wValue >> 8); - uint8_t response = slaveReadDigital(port, mask); - memcpy(response_buffer, &response, sizeof(response)); - return sizeof(response); - } + case COMMAND_READ_PERIPHERAL_VALID: + response_buffer[0] = slave_initted; + return 1; + case COMMAND_READ_PERIPHERAL_DIGITAL: + { + uint8_t port = wValue & 0xff; + uint8_t mask = (wValue >> 8); + uint8_t response = slaveReadDigital(port, mask); + memcpy(response_buffer, &response, sizeof(response)); + return sizeof(response); + } + case COMMAND_READ_PERIPHERAL_ENCODER: + { + int response = slaveReadQuad(); + memcpy(response_buffer, &response, sizeof(response)); + return sizeof(response); + } #endif #if LED_COUNT_WS2812 - case COMMAND_SET_LEDS: { - uint8_t led = response_buffer[0]; - if (led >= LED_COUNT_WS2812) return 0; - if (response_buffer[1] == 0 && response_buffer[2] == 0 && response_buffer[3] == 0) { - ledState[led].select = 0; - return 0; - } - memcpy(&ledState[led], response_buffer, sizeof(Led_WS2812_t)); - ledState[led].select = 1; + case COMMAND_SET_LEDS: + { + uint8_t led = response_buffer[0]; + if (led >= LED_COUNT_WS2812) + return 0; + if (response_buffer[1] == 0 && response_buffer[2] == 0 && response_buffer[3] == 0) + { + ledState[led].select = 0; return 0; } + memcpy(&ledState[led], response_buffer, sizeof(Led_WS2812_t)); + ledState[led].select = 1; + return 0; + } #endif #if LED_COUNT_PERIPHERAL_WS2812 - case COMMAND_SET_LEDS_PERIPHERAL: { - uint8_t led = response_buffer[0]; - if (led >= LED_COUNT_PERIPHERAL_WS2812) return 0; - if (response_buffer[1] == 0 && response_buffer[2] == 0 && response_buffer[3] == 0) { - ledStatePeripheral[led].select = 0; - return 0; - } - memcpy(&ledStatePeripheral[led], response_buffer, sizeof(Led_WS2812_t)); - ledStatePeripheral[led].select = 1; + case COMMAND_SET_LEDS_PERIPHERAL: + { + uint8_t led = response_buffer[0]; + if (led >= LED_COUNT_PERIPHERAL_WS2812) + return 0; + if (response_buffer[1] == 0 && response_buffer[2] == 0 && response_buffer[3] == 0) + { + ledStatePeripheral[led].select = 0; return 0; } + memcpy(&ledStatePeripheral[led], response_buffer, sizeof(Led_WS2812_t)); + ledStatePeripheral[led].select = 1; + return 0; + } #endif #if LED_COUNT - case COMMAND_SET_LEDS: { - uint8_t led = response_buffer[0]; - if (led >= LED_COUNT) return 0; - if (response_buffer[2] == 0 && response_buffer[3] == 0 && response_buffer[4] == 0) { - ledState[led].select = 0; - return 0; - } - ledState[led].select = 1; - ledState[led].brightness = response_buffer[1]; - ledState[led].r = response_buffer[2]; - ledState[led].g = response_buffer[3]; - ledState[led].b = response_buffer[4]; + case COMMAND_SET_LEDS: + { + uint8_t led = response_buffer[0]; + if (led >= LED_COUNT) + return 0; + if (response_buffer[2] == 0 && response_buffer[3] == 0 && response_buffer[4] == 0) + { + ledState[led].select = 0; return 0; } + ledState[led].select = 1; + ledState[led].brightness = response_buffer[1]; + ledState[led].r = response_buffer[2]; + ledState[led].g = response_buffer[3]; + ledState[led].b = response_buffer[4]; + return 0; + } #endif #if LED_COUNT_PERIPHERAL - case COMMAND_SET_LEDS_PERIPHERAL: { - uint8_t led = response_buffer[0]; - if (led >= LED_COUNT_PERIPHERAL) return 0; - if (response_buffer[2] == 0 && response_buffer[3] == 0 && response_buffer[4] == 0) { - ledStatePeripheral[led].select = 0; - return 0; - } - ledStatePeripheral[led].select = 1; - ledStatePeripheral[led].brightness = response_buffer[1]; - ledStatePeripheral[led].r = response_buffer[2]; - ledStatePeripheral[led].g = response_buffer[3]; - ledStatePeripheral[led].b = response_buffer[4]; + case COMMAND_SET_LEDS_PERIPHERAL: + { + uint8_t led = response_buffer[0]; + if (led >= LED_COUNT_PERIPHERAL) + return 0; + if (response_buffer[2] == 0 && response_buffer[3] == 0 && response_buffer[4] == 0) + { + ledStatePeripheral[led].select = 0; return 0; } + ledStatePeripheral[led].select = 1; + ledStatePeripheral[led].brightness = response_buffer[1]; + ledStatePeripheral[led].r = response_buffer[2]; + ledStatePeripheral[led].g = response_buffer[3]; + ledStatePeripheral[led].b = response_buffer[4]; + return 0; + } #endif #if LED_COUNT_MPR121 - case COMMAND_SET_LEDS_MPR121: { - uint8_t led = response_buffer[0]; - if (led >= LED_COUNT_MPR121) return 0; - if (response_buffer[1]) { - bit_set(ledStateMpr121, led % 8); - bit_set(ledStateMpr121Select, led % 8); - } else { - bit_clear(ledStateMpr121, led % 8); - bit_clear(ledStateMpr121Select, led % 8); - } + case COMMAND_SET_LEDS_MPR121: + { + uint8_t led = response_buffer[0]; + if (led >= LED_COUNT_MPR121) return 0; + if (response_buffer[1]) + { + bit_set(ledStateMpr121, led % 8); + bit_set(ledStateMpr121Select, led % 8); + } + else + { + bit_clear(ledStateMpr121, led % 8); + bit_clear(ledStateMpr121Select, led % 8); } + return 0; + } #endif #if LED_COUNT_STP - case COMMAND_SET_LEDS: { - uint8_t led = response_buffer[0]; - if (led >= LED_COUNT_STP) return 0; - if (response_buffer[1]) { - bit_set(ledState[led >> 3], led % 8); - bit_set(ledStateSelect[led >> 3], led % 8); - } else { - bit_clear(ledState[led >> 3], led % 8); - bit_clear(ledStateSelect[led >> 3], led % 8); - } + case COMMAND_SET_LEDS: + { + uint8_t led = response_buffer[0]; + if (led >= LED_COUNT_STP) return 0; + if (response_buffer[1]) + { + bit_set(ledState[led >> 3], led % 8); + bit_set(ledStateSelect[led >> 3], led % 8); } + else + { + bit_clear(ledState[led >> 3], led % 8); + bit_clear(ledStateSelect[led >> 3], led % 8); + } + return 0; + } #endif #if LED_COUNT_PERIPHERAL_STP - case COMMAND_SET_LEDS_PERIPHERAL: { - uint8_t led = response_buffer[0]; - if (led >= LED_COUNT_PERIPHERAL_STP) return 0; - if (response_buffer[1]) { - bit_set(ledStatePeripheral[led >> 3], led % 8); - bit_set(ledStatePeripheralSelect[led >> 3], led % 8); - } else { - bit_clear(ledStatePeripheral[led >> 3], led % 8); - bit_clear(ledStatePeripheralSelect[led >> 3], led % 8); - } + case COMMAND_SET_LEDS_PERIPHERAL: + { + uint8_t led = response_buffer[0]; + if (led >= LED_COUNT_PERIPHERAL_STP) return 0; + if (response_buffer[1]) + { + bit_set(ledStatePeripheral[led >> 3], led % 8); + bit_set(ledStatePeripheralSelect[led >> 3], led % 8); + } + else + { + bit_clear(ledStatePeripheral[led >> 3], led % 8); + bit_clear(ledStatePeripheralSelect[led >> 3], led % 8); } + return 0; + } #endif #ifdef INPUT_USB_HOST - case COMMAND_READ_USB_HOST: { - return read_usb_host_devices(response_buffer); - } - case COMMAND_READ_USB_HOST_INPUTS: { - memcpy(response_buffer, &last_usb_host_data, sizeof(last_usb_host_data)); - return sizeof(last_usb_host_data); - } + case COMMAND_READ_USB_HOST: + { + return read_usb_host_devices(response_buffer); + } + case COMMAND_READ_USB_HOST_INPUTS: + { + memcpy(response_buffer, &last_usb_host_data, sizeof(last_usb_host_data)); + return sizeof(last_usb_host_data); + } #endif #if BLUETOOTH_RX - case COMMAND_START_BT_SCAN: { - bt_start_scan(); - return 0; - } - case COMMAND_STOP_BT_SCAN: { - bt_stop_scan(); - return 0; - } - case COMMAND_GET_BT_DEVICES: { - return bt_get_scan_results(response_buffer); - } - case COMMAND_READ_BLUETOOTH_INPUTS: { - memcpy(response_buffer, &bt_data, sizeof(bt_data)); - return sizeof(bt_data); - } + case COMMAND_START_BT_SCAN: + { + bt_start_scan(); + return 0; + } + case COMMAND_STOP_BT_SCAN: + { + bt_stop_scan(); + return 0; + } + case COMMAND_GET_BT_DEVICES: + { + return bt_get_scan_results(response_buffer); + } + case COMMAND_READ_BLUETOOTH_INPUTS: + { + memcpy(response_buffer, &bt_data, sizeof(bt_data)); + return sizeof(bt_data); + } #endif #if BLUETOOTH - case COMMAND_GET_BT_STATE: { - response_buffer[0] = check_bluetooth_ready(); - return 1; - } - case COMMAND_GET_BT_ADDRESS: { - return get_bt_address(response_buffer); - } + case COMMAND_GET_BT_STATE: + { + response_buffer[0] = check_bluetooth_ready(); + return 1; + } + case COMMAND_GET_BT_ADDRESS: + { + return get_bt_address(response_buffer); + } #endif } *success = false; return 0; } -uint8_t hid_get_report(uint8_t *data, uint8_t reqlen, uint8_t reportType, uint8_t report_id) { +uint8_t hid_get_report(uint8_t *data, uint8_t reqlen, uint8_t reportType, uint8_t report_id) +{ return 0; } \ No newline at end of file diff --git a/src/shared/hid/ps3_wii_switch.h b/src/shared/hid/ps3_wii_switch.h index 3d144c220..3fd9ed435 100644 --- a/src/shared/hid/ps3_wii_switch.h +++ b/src/shared/hid/ps3_wii_switch.h @@ -2,6 +2,49 @@ #include "config.h" #include "progmem.h" +const uint8_t PROGMEM gha_descriptor[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x15, 0x00, // Logical Minimum (0) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0x05, 0x02, // Usage Page (Simulation Controls) + 0x09, 0xBB, // Usage (Throttle) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7f, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x00, // Report Cout (0) + 0x81, 0x02, // Input (Data,Var,Abs) + 0x05, 0x01, // Usage Page (Generic Desktop Controls) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x33, // Usage (Rx) + 0x09, 0x34, // Usage (Ry) + 0x95, 0x05, // Report Count (5) + 0x81, 0x02, // Input (Data,Var,Abs) + 0xC0, // End Collection + 0x09, 0x39, // Usage (Hat switch) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x03, // Logical Maximum (3) + 0x46, 0x0E, 0x01, // Physical Maximum (270) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (5) + 0x81, 0x02, // Input (Data,Var,Abs) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0A, // Usage Maximum (0x0A) + 0x15, 0x01, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0C, // Report Count (12) + 0x55, 0x00, // Unit Exponent (-16) + 0x65, 0x00, // Unit Exponent (0x00) + 0x81, 0x02, // Input (Data,Var,Abs) + 0xC0, // End Collection +}; const uint8_t PROGMEM ps3_instrument_descriptor[] = { 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x05, // Usage (Game Pad) @@ -438,3 +481,86 @@ const uint8_t PROGMEM ps4_descriptor[] = { 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xC0, // End Collection }; + +const uint8_t PROGMEM ps5_descriptor[] = +{ + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x05, // Usage (Game Pad) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x01, // Report ID (1) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x09, 0x33, // Usage (Rx) + 0x09, 0x34, // Usage (Ry) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x06, // Report Count (6) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x09, 0x20, // Usage (0x20) + 0x95, 0x01, // Report Count (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x39, // Usage (Hat switch) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x07, // Logical Maximum (7) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0E, // Usage Maximum (0x0E) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0E, // Report Count (14) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x09, 0x21, // Usage (0x21) + 0x95, 0x0E, // Report Count (14) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x09, 0x22, // Usage (0x22) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x34, // Report Count (52) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x85, 0x02, // Report ID (2) + 0x09, 0x23, // Usage (0x23) + 0x95, 0x2F, // Report Count (47) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x03, // Report ID (3) + 0x0A, 0x21, 0x28, // Usage (0x2821) + 0x95, 0x2F, // Report Count (47) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80) + 0x85, 0xE0, // Report ID (-32) + 0x09, 0x57, // Usage (0x57) + 0x95, 0x02, // Report Count (2) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0x06, 0xF0, 0xFF, // Usage Page (Vendor Defined 0xFFF0) + 0x09, 0x40, // Usage (0x40) + 0xA1, 0x01, // Collection (Application) + 0x85, 0xF0, // Report ID (-16) + 0x09, 0x47, // Usage (0x47) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF1, // Report ID (-15) + 0x09, 0x48, // Usage (0x48) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xF2, // Report ID (-14) + 0x09, 0x49, // Usage (0x49) + 0x95, 0x0F, // Report Count (15) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection +}; diff --git a/src/shared/main/accel.cpp b/src/shared/main/accel.cpp index 8097d3702..c5c62900a 100644 --- a/src/shared/main/accel.cpp +++ b/src/shared/main/accel.cpp @@ -8,29 +8,49 @@ uint16_t accel_adc[3] = {0}; double currentLowPassAlpha = LOW_PASS_ALPHA; bool accel_found = false; uint8_t lis3dh_address = LIS3DH_ADDRESS; +uint8_t mpu6050_address = MPU6050_ADDRESS; uint8_t type = NONE; #ifdef ACCEL_TWI_PORT -void init_lis3dh() { +void init_lis3dh() +{ uint8_t id = 0; lis3dh_address = LIS3DH_ADDRESS; twi_readFromPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_WHOAMI, 1, &id); - lis3dh_address = LIS3DH_ADDRESS_2; - if (id != LIS3DH_ID) { + if (id != LIS3DH_ID && id != SC7A20_ID && id != LIS3DSH_ID) + { + lis3dh_address = LIS3DH_ADDRESS_2; twi_readFromPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_WHOAMI, 1, &id); - if (id != LIS3DH_ID) { + if (id != LIS3DH_ID && id != SC7A20_ID && id != LIS3DSH_ID) + { return; } } - type = LIS3DH; accel_found = true; - twi_writeSingleToPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_CTRL1, 0b01110111); // enable all axis, set data rate to 4000hz - twi_writeSingleToPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_CTRL4, 0x88); // High res & BDU enabled - twi_writeSingleToPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_TEMPCFG, 0x80); // enable adc + if (id == SC7A20_ID) + { + type = SC7A20; + twi_writeSingleToPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_CTRL1, 0b01110111); // enable all axis, set data rate to 4000hz + twi_writeSingleToPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_CTRL4, 0x88); // High res & BDU enabled + } + else if (id == LIS3DSH_ID) + { + type = LIS3DSH; + twi_writeSingleToPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_CTRL1, 0b01111111); // enable all axis, BDU, set data rate to 4000hz + } + else + { + type = LIS3DH; + twi_writeSingleToPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_CTRL1, 0b01110111); // enable all axis, set data rate to 4000hz + twi_writeSingleToPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_CTRL4, 0x88); // High res & BDU enabled + twi_writeSingleToPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_TEMPCFG, 0x80); // enable adc + } } -void init_adxl() { +void init_adxl() +{ uint8_t id = 0; twi_readFromPointer(ACCEL_TWI_PORT, ADXL345_ADDRESS, ADXL345_REG_DEVID, 1, &id); - if (id != ADXL345_ID) { + if (id != ADXL345_ID) + { return; } type = ADXL345; @@ -38,47 +58,99 @@ void init_adxl() { twi_writeSingleToPointer(ACCEL_TWI_PORT, ADXL345_ADDRESS, ADXL345_POWER_CTL, 0x08); twi_writeSingleToPointer(ACCEL_TWI_PORT, ADXL345_ADDRESS, ADXL345_DATA_FORMAT, 0x0B); } -void init_mpu6050() { +static bool probe_mpu6050(uint8_t address) +{ uint8_t id = 0; - twi_readFromPointer(ACCEL_TWI_PORT, MPU6050_ADDRESS, MPU6050_REG_WHO_AM_I, 1, &id); - if (id != MPU6050_ID) { + return twi_readFromPointerRepeatedStart(ACCEL_TWI_PORT, address, MPU6050_REG_WHO_AM_I, 1, &id) && + (id == MPU6050_ID || id == MPU6050_ID2 || id == MPU6050_ID3); +} + +void init_mpu6050() +{ + uint8_t address = MPU6050_ADDRESS; + if (!probe_mpu6050(address)) + { + address = MPU6050_ADDRESS_ALT; + if (!probe_mpu6050(address)) + { + return; + } + } + + uint8_t power_management = 0; + if (!twi_readFromPointerRepeatedStart(ACCEL_TWI_PORT, address, MPU6050_REG_PWR_MGMT_1, 1, &power_management)) + { + return; + } + + power_management &= (uint8_t) ~(MPU6050_PWR1_SLEEP | MPU6050_PWR1_CLKSEL_MASK); + power_management |= MPU6050_PWR1_CLKSEL_XGYRO; + if (!twi_writeSingleToPointer(ACCEL_TWI_PORT, address, MPU6050_REG_PWR_MGMT_1, power_management)) + { return; } + + if (!twi_writeSingleToPointer(ACCEL_TWI_PORT, address, MPU6050_REG_ACCEL_CONFIG, MPU6050_ACCEL_CONFIG_2G)) + { + return; + } + + mpu6050_address = address; type = MPU6050; accel_found = true; - twi_writeSingleToPointer(ACCEL_TWI_PORT, MPU6050_ADDRESS, MPU6050_REG_ACCEL_CONFIG, 0b11100111); - twi_readFromPointer(ACCEL_TWI_PORT, MPU6050_ADDRESS, MPU6050_REG_PWR_MGMT_1, 1, &id); - id &= ~(1 << 6); - twi_writeSingleToPointer(ACCEL_TWI_PORT, MPU6050_ADDRESS, MPU6050_REG_PWR_MGMT_1, id); } -void init_accel() { +void init_accel() +{ + init_mpu6050(); init_lis3dh(); init_adxl(); - init_mpu6050(); } -void tick_accel() { - if (!accel_found) { +void tick_accel() +{ + int16_t raw[3]; + if (!accel_found) + { + for (int i = 0; i < 3; i++) + { + filtered[i] = raw[i] = 0; + } init_accel(); return; } - int16_t raw[3]; - if (type == LIS3DH) { - accel_found = twi_readFromPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_OUT, 6, (uint8_t*)raw); - accel_found = twi_readFromPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_OUTADC1_L, sizeof(accel_adc), (uint8_t*)accel_adc); - for (int i = 0; i < 3; i++) { + if (type == LIS3DH) + { + accel_found = twi_readFromPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_OUT, 6, (uint8_t *)raw); + accel_found = twi_readFromPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_OUTADC1_L, sizeof(accel_adc), (uint8_t *)accel_adc); + for (int i = 0; i < 3; i++) + { + filtered[i] = (raw[i]) * currentLowPassAlpha + (filtered[i] * (1.0 - currentLowPassAlpha)); + } + } + if (type == SC7A20 || type == LIS3DSH) + { + accel_found = twi_readFromPointer(ACCEL_TWI_PORT, lis3dh_address, LIS3DH_REG_OUT, 6, (uint8_t *)raw); + for (int i = 0; i < 3; i++) + { filtered[i] = (raw[i]) * currentLowPassAlpha + (filtered[i] * (1.0 - currentLowPassAlpha)); } } - if (type == ADXL345) { - accel_found = twi_readFromPointer(ACCEL_TWI_PORT, ADXL345_ADDRESS, ADXL345_DATAX0, 6, (uint8_t*)raw); - for (int i = 0; i < 3; i++) { + if (type == ADXL345) + { + accel_found = twi_readFromPointer(ACCEL_TWI_PORT, ADXL345_ADDRESS, ADXL345_DATAX0, 6, (uint8_t *)raw); + for (int i = 0; i < 3; i++) + { filtered[i] = (raw[i] * 64) * currentLowPassAlpha + (filtered[i] * (1.0 - currentLowPassAlpha)); } } - if (type == MPU6050) { - accel_found = twi_readFromPointer(ACCEL_TWI_PORT, MPU6050_ADDRESS, MPU6050_REG_ACCEL_OUT, 6, (uint8_t*)raw); - for (int i = 0; i < 3; i++) { - filtered[i] = (raw[i]) * currentLowPassAlpha + (filtered[i] * (1.0 - currentLowPassAlpha)); + if (type == MPU6050) + { + uint8_t raw_bytes[6]; + accel_found = twi_readFromPointerRepeatedStart(ACCEL_TWI_PORT, mpu6050_address, MPU6050_REG_ACCEL_OUT, + sizeof(raw_bytes), raw_bytes); + for (int i = 0; i < 3; i++) + { + raw[i] = (int16_t) (((uint16_t) raw_bytes[i * 2] << 8) | raw_bytes[i * 2 + 1]); + filtered[i] = raw[i] * currentLowPassAlpha + (filtered[i] * (1.0 - currentLowPassAlpha)); } } } diff --git a/src/shared/main/ads1115.cpp b/src/shared/main/ads1115.cpp new file mode 100644 index 000000000..07c121310 --- /dev/null +++ b/src/shared/main/ads1115.cpp @@ -0,0 +1,70 @@ +#include +#include "io.h" +#include "ads1115.h" +#ifdef ADS115_TWI_PORT +static uint16_t config; +static volatile bool rdy; +static bool connected = false; +static uint8_t current = 0; +static uint16_t inputs[4]; +bool writeRegister(uint8_t reg, uint16_t val) +{ + uint8_t data[] = {(uint8_t)((val >> 8) & 0xFF), (uint8_t)(val & 0xFF)}; + return twi_writeToPointer(ADS115_TWI_PORT, ADS1115_ADDRESS_ADDR_GND, reg, sizeof(data), data); +} +uint16_t readRegister(uint8_t reg) +{ + uint8_t data[2] = {}; + if (!twi_readFromPointer(ADS115_TWI_PORT, ADS1115_ADDRESS_ADDR_GND, reg, sizeof(data), data)) + { + return 0; + } + return (data[0] << 8) + data[1]; +} +void tick() +{ + if (!connected) + { + init(); + return; + } + config = readRegister(ADS1115_RA_CONFIG); + if (rdy) + { + rdy = false; + inputs[current] = readRegister(ADS1115_RA_CONVERSION) << 1; + current++; + if (current > 3) + { + current = 0; + } + config &= ~(0xF000); + config |= (0x4000 + (current * 0x1000)); + config |= 1<<15; + connected = writeRegister(ADS1115_RA_CONFIG, config); + + } +} +void cb(uint gpio, uint32_t event_mask) { + rdy = true; +} +void init() +{ + if (!readRegister(ADS1115_RA_CONFIG)) + { + connected = false; + return; + } + connected = true; + current = 0; + gpio_init(ADS115_ALERT); + gpio_set_dir(ADS115_ALERT, false); + gpio_pull_up(ADS115_ALERT); + + gpio_set_irq_enabled_with_callback(ADS115_ALERT, GPIO_IRQ_EDGE_FALL, true, &cb); + config = ADS1115_REG_RESET_VAL; + connected = writeRegister(ADS1115_RA_CONFIG, ADS1115_REG_RESET_VAL); + connected = writeRegister(ADS1115_RA_LO_THRESH, (0 << 15)); + connected = writeRegister(ADS1115_RA_HI_THRESH, (1 << 15)); +} +#endif \ No newline at end of file diff --git a/src/shared/main/bh_drum.cpp b/src/shared/main/bh_drum.cpp index 793d3e805..19ed796be 100644 --- a/src/shared/main/bh_drum.cpp +++ b/src/shared/main/bh_drum.cpp @@ -3,28 +3,35 @@ #include "Arduino.h" #include "io.h" #include "shared_main.h" +#include "state_translation/drums.h" #define DRUM_ADDR 0x0D #define BH_DRUM_PTR 0x10 #ifdef BH_DRUM_TWI_PORT -static long lastTick = 0; -static int missing = 0; -bool wt_drum_found = false; -void tickBhDrum() { - // BH Drum format: 0x10 - uint8_t data[8]; - if (twi_readFromPointer(BH_DRUM_TWI_PORT, DRUM_ADDR, BH_DRUM_PTR, sizeof(data), data) && data[0] == BH_DRUM_PTR) { - uint8_t status = data[1]; - uint8_t type = (status & 0xf0); - uint8_t channel = status & 0x0f; - // TODO: CC and stuff, can the midi lib parse this all for us? - if (type == 0x90) { - uint8_t note = data[2]; - uint8_t velocity = data[3]; - onNote(channel, note, velocity); - } else if (type == 0x80) { - uint8_t note = data[2]; - uint8_t velocity = data[3]; - offNote(channel, note, velocity); +bool bh_drum_found = false; +void tickBhDrum() +{ + // Drum packet starts with some counter, and then the number of packets in the buffer + uint8_t header[2]; + uint8_t data[3]; + bh_drum_found = twi_readFromPointerRepeatedStart(BH_DRUM_TWI_PORT, DRUM_ADDR, BH_DRUM_PTR, sizeof(header), header); + if (bh_drum_found) + { + // Stream out the rest of the packets byte by byte as the drums lock up otherwise. + uint8_t count = header[1] >> 4; + for (int i = 0; i < count; i++) + { + bh_drum_found = twi_readFrom(BH_DRUM_TWI_PORT, DRUM_ADDR, data, sizeof(data), true); + uint8_t type = (data[0] & 0xf0); + uint8_t channel = data[0] & 0x0f; + // TODO: CC and stuff, can the midi lib parse this all for us? + if (type == 0x90) + { + TRANSLATE_GH_MIDI(channel, data[1], data[2], onNote); + } + else if (type == 0x80) + { + TRANSLATE_GH_MIDI(channel, data[1], data[2], offNote); + } } } } diff --git a/src/shared/main/gh5_neck.cpp b/src/shared/main/gh5_neck.cpp new file mode 100644 index 000000000..45d478e5c --- /dev/null +++ b/src/shared/main/gh5_neck.cpp @@ -0,0 +1,20 @@ +#include + +#include "Arduino.h" +#include "io.h" +#include "shared_main.h" +#include "commands.h" +#define GH5NECK_ADDR 0x0D +#define GH5NECK_BUTTONS_PTR 0x11 +bool lastGH5WasSuccessful = false; +#ifdef GH5_TWI_PORT +void tickGh5Neck() +{ + uint8_t header; + lastGH5WasSuccessful = twi_readFromPointerRepeatedStart(GH5_TWI_PORT, GH5NECK_ADDR, GH5NECK_BUTTONS_PTR, 1, &header); + if (lastGH5WasSuccessful && header) + { + lastGH5WasSuccessful = twi_readFrom(GH5_TWI_PORT, GH5NECK_ADDR, lastSuccessfulGH5Packet, sizeof(lastSuccessfulGH5Packet), true); + } +} +#endif \ No newline at end of file diff --git a/src/shared/main/inputs/crkd.h b/src/shared/main/inputs/crkd.h new file mode 100644 index 000000000..17b3317f4 --- /dev/null +++ b/src/shared/main/inputs/crkd.h @@ -0,0 +1,10 @@ +#ifdef INPUT_CRKD_NECK +lastCrkdWasSuccessful = read_uart(CRKD_UART_PORT, 0xA5, 11, (uint8_t *)&lastCrkd); +if (lastCrkdWasSuccessful && millis() - lastCrkdSend > 10) + { + // kick the neck over to polling at 1ms + uint8_t data[] = {0xA5, 0xC1, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5}; + send_uart(CRKD_UART_PORT, data, sizeof(data)); + lastCrkdSend = millis(); + } +#endif \ No newline at end of file diff --git a/src/shared/main/inputs/gh5_neck.h b/src/shared/main/inputs/gh5_neck.h index ff66d4e47..c66f4b29e 100644 --- a/src/shared/main/inputs/gh5_neck.h +++ b/src/shared/main/inputs/gh5_neck.h @@ -1,5 +1,4 @@ #ifdef INPUT_GH5_NECK - uint8_t *fivetar_buttons = lastSuccessfulGH5Packet; - bool gh5Valid = twi_readFromPointer(GH5_TWI_PORT, GH5NECK_ADDR, GH5NECK_BUTTONS_PTR, sizeof(lastSuccessfulGH5Packet), lastSuccessfulGH5Packet); - lastGH5WasSuccessful = gh5Valid; +uint8_t *fivetar_buttons = lastSuccessfulGH5Packet; +tickGh5Neck(); #endif \ No newline at end of file diff --git a/src/shared/main/inputs/midi_fader.h b/src/shared/main/inputs/midi_fader.h new file mode 100644 index 000000000..82e748372 --- /dev/null +++ b/src/shared/main/inputs/midi_fader.h @@ -0,0 +1,3 @@ +#ifdef INPUT_MIDI_FADER +lastMidiFaderWasSuccessful = read_uart(MIDI_FADER_UART_PORT, 1, (uint8_t *)&lastMidiFader); +#endif \ No newline at end of file diff --git a/src/shared/main/inputs/mustang_neck.h b/src/shared/main/inputs/mustang_neck.h new file mode 100644 index 000000000..ab9eac7b0 --- /dev/null +++ b/src/shared/main/inputs/mustang_neck.h @@ -0,0 +1,3 @@ +#ifdef MUSTANG_NECK_SPI_PORT +lastProtar = tickMustangNeck(); +#endif \ No newline at end of file diff --git a/src/shared/main/inputs/slave.h b/src/shared/main/inputs/slave.h index d546ba8b7..d3a74fcd9 100644 --- a/src/shared/main/inputs/slave.h +++ b/src/shared/main/inputs/slave.h @@ -92,6 +92,35 @@ void slaveWriteLED(uint8_t data) { } } +void slaveInitQuad(uint8_t pin, uint8_t rate) { + if (!slave_initted) { + return; + } + uint8_t data[] = {pin, rate}; + for (int i = 0; i < RETRY_COUNT; i++) { + slave_initted = twi_writeToPointer(SLAVE_TWI_PORT, SLAVE_ADDR, SLAVE_COMMAND_INIT_QUAD, sizeof(data), data); + if (slave_initted) { + return; + } + } +} +int32_t slaveReadQuad() { + if (!slave_initted) { + return 0; + } + for (int i = 0; i < RETRY_COUNT; i++) { + int32_t data = 0; + slave_initted = twi_readFromPointer(SLAVE_TWI_PORT, SLAVE_ADDR, SLAVE_COMMAND_GET_QUAD, sizeof(data), (uint8_t*)&data); + #if DEVICE_TYPE == DJ_HERO_TURNTABLE + data <<= 9; + #endif + if (slave_initted) { + return data; + } + } + return 0; +} + uint8_t slaveReadWt() { if (!slave_initted) { return 0; diff --git a/src/shared/main/inputs/turntable.h b/src/shared/main/inputs/turntable.h index a8db8f837..65e822bd8 100644 --- a/src/shared/main/inputs/turntable.h +++ b/src/shared/main/inputs/turntable.h @@ -1,4 +1,13 @@ #include "config.h" + +#ifdef INPUT_QUAD + if ((lastQuadPoll - millis()) > 1) { + lastQuadPoll = millis(); + new_value = quadrature_encoder_get_count(pio, sm); + delta = new_value - old_value; + old_value = new_value; + } +#endif #ifdef INPUT_DJ_TURNTABLE uint8_t *dj_left = lastSuccessfulTurntablePacketLeft; uint8_t *dj_right = lastSuccessfulTurntablePacketRight; diff --git a/src/shared/main/inputs/usb_host.h b/src/shared/main/inputs/usb_host.h index d3519d284..b5cdf695f 100644 --- a/src/shared/main/inputs/usb_host.h +++ b/src/shared/main/inputs/usb_host.h @@ -19,9 +19,9 @@ for (int i = 0; i < device_count; i++) { // Poke any GHL guitars to keep em alive if (poke_ghl && device_type.sub_type == LIVE_GUITAR) { if (device_type.console_type == PS3) { - transfer_with_usb_controller(device_type.dev_addr, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS, HID_REQUEST_SET_REPORT, 0x0201, 0, sizeof(ghl_ps3wiiu_magic_data), ghl_ps3wiiu_magic_data, NULL); + transfer_with_usb_controller(device_type, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS, HID_REQUEST_SET_REPORT, 0x0201, sizeof(ghl_ps3wiiu_magic_data), ghl_ps3wiiu_magic_data, NULL); } else if (device_type.console_type == PS4) { - transfer_with_usb_controller(device_type.dev_addr, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS, HID_REQUEST_SET_REPORT, 0x0201, 0, sizeof(ghl_ps4_magic_data), ghl_ps4_magic_data, NULL); + transfer_with_usb_controller(device_type, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS, HID_REQUEST_SET_REPORT, 0x0201, sizeof(ghl_ps4_magic_data), ghl_ps4_magic_data, NULL); } else if (device_type.console_type == XBOXONE) { if (ghl_sequence_number_host == 0) { ghl_sequence_number_host = 1; diff --git a/src/shared/main/mustang_neck.cpp b/src/shared/main/mustang_neck.cpp new file mode 100644 index 000000000..ee962b7eb --- /dev/null +++ b/src/shared/main/mustang_neck.cpp @@ -0,0 +1,42 @@ +#include + +#include "Arduino.h" +#include "io.h" +#include "shared_main.h" +#include "state_translation/pro_guitar.h" +#ifdef MUSTANG_NECK_SPI_PORT +static long lastTick = 0; +static int missing = 0; +bool mustang_neck_found = false; +static protarneck_t neck; +protarneck_t tickMustangNeck() +{ + if (micros() - lastTick > 500) + { + lastTick = micros(); + MUSTANG_NECK_CS_CLEAR(); + uint8_t resp = spi_transfer(MUSTANG_NECK_SPI_PORT, 0x80); + if (resp == 0x00) + { + mustang_neck_found = true; + memset(&neck, 0, sizeof(neck)); + MUSTANG_NECK_CS_SET(); + return neck; + } + if (resp != 0x80) + { + mustang_neck_found = false; + MUSTANG_NECK_CS_SET(); + return neck; + } + mustang_neck_found = true; + uint8_t *buf = (uint8_t *)&neck; + for (int i = 0; i < sizeof(neck); i++) + { + buf[i] = spi_transfer(MUSTANG_NECK_SPI_PORT, 0x12); + } + MUSTANG_NECK_CS_SET(); + } + return neck; +} +#endif \ No newline at end of file diff --git a/src/shared/main/ps2.cpp b/src/shared/main/ps2.cpp index fc67e0f45..3b8e39d39 100644 --- a/src/shared/main/ps2.cpp +++ b/src/shared/main/ps2.cpp @@ -8,41 +8,51 @@ #include "util.h" #ifdef INPUT_PS2 -static inline bool isValidReply(const uint8_t *status) { +static inline bool isValidReply(const uint8_t *status) +{ return status[1] != 0xFF && (status[2] == 0x5A || status[2] == 0x00); } -static inline bool isFlightStickReply(const uint8_t *status) { +static inline bool isFlightStickReply(const uint8_t *status) +{ return (status[1] & 0xF0) == 0x50; } -static inline bool isNegconReply(const uint8_t *status) { +static inline bool isNegconReply(const uint8_t *status) +{ return status[1] == 0x23; } -static inline bool isJogconReply(const uint8_t *status) { +static inline bool isJogconReply(const uint8_t *status) +{ return (status[1] & 0xF0) == 0xE0; } -static inline bool isGunconReply(const uint8_t *status) { +static inline bool isGunconReply(const uint8_t *status) +{ return status[1] == 0x63; } -static inline bool isMouseReply(const uint8_t *status) { +static inline bool isMouseReply(const uint8_t *status) +{ return status[1] == 0x12; } -static inline bool isDualShockReply(const uint8_t *status) { +static inline bool isDualShockReply(const uint8_t *status) +{ return (status[1] & 0xF0) == 0x70; } -static inline bool isDualShock2Reply(const uint8_t *status) { +static inline bool isDualShock2Reply(const uint8_t *status) +{ return status[1] == 0x79; } -static inline bool isDigitalReply(const uint8_t *status) { +static inline bool isDigitalReply(const uint8_t *status) +{ return (status[1] & 0xF0) == 0x40; } -static inline bool isConfigReply(const uint8_t *status) { +static inline bool isConfigReply(const uint8_t *status) +{ return (status[1] & 0xF0) == 0xF0; } static const uint8_t commandEnterConfig[] = {0x43, 0x00, 0x01, 0x5A, @@ -55,7 +65,7 @@ static const uint8_t commandGetStatus[] = {0x45, 0x00, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A}; static const uint8_t commandGetExtra[] = {0x46, 0x00, 0x00, 0x5A, - 0x5A, 0xA, 0x5A, 0x5A}; + 0x5A, 0xA, 0x5A, 0x5A}; static const uint8_t commandGetExtra2[] = {0x46, 0x00, 0x00, 0x5A, 0x5A, 0xA, 0x5A, 0x5A}; @@ -89,29 +99,36 @@ static const uint8_t commandPollInput[] = {0x42, 0x00, 0xFF, 0xFF}; static bool initialised = false; static long last = 0; static uint8_t invalidCount = 0; -void noAttention(void) { +void noAttention(void) +{ spi_high(PS2_SPI_PORT); INPUT_PS2_ATT_SET(); delayMicroseconds(ATTN_DELAY); } -void signalAttention(void) { +void signalAttention(void) +{ INPUT_PS2_ATT_CLEAR(); delayMicroseconds(ATTN_DELAY); } -void shiftDataInOut(const uint8_t *out, uint8_t *in, const uint8_t len) { +void shiftDataInOut(const uint8_t *out, uint8_t *in, const uint8_t len) +{ unsigned long m; - for (uint8_t i = 0; i < len; ++i) { + for (uint8_t i = 0; i < len; ++i) + { uint8_t resp = spi_transfer(PS2_SPI_PORT, out != NULL ? out[i] : 0x5A); - if (in != NULL) { + if (in != NULL) + { in[i] = resp; } spi_acknowledged = false; m = micros(); - while (!spi_acknowledged) { + while (!spi_acknowledged) + { // If for some reason the controller doesn't respond to us, we need to // make sure we finish the transfer anyways - if (micros() - m > INTER_CMD_BYTE_DELAY) { + if (micros() - m > INTER_CMD_BYTE_DELAY) + { break; } } @@ -119,15 +136,18 @@ void shiftDataInOut(const uint8_t *out, uint8_t *in, const uint8_t len) { } static uint8_t inputBuffer[BUFFER_SIZE]; static uint8_t inputBuffer2[BUFFER_SIZE]; -uint8_t *autoShiftData(uint8_t port, const uint8_t *out, const uint8_t len) { +uint8_t *autoShiftData(uint8_t port, const uint8_t *out, const uint8_t len) +{ uint8_t *ret = NULL; - if (len >= 2 && len <= BUFFER_SIZE) { + if (len >= 2 && len <= BUFFER_SIZE) + { signalAttention(); // All commands have at least 3 bytes, so shift out those first shiftDataInOut(&port, inputBuffer, 1); shiftDataInOut(out, inputBuffer + 1, 2); - if (isValidReply(inputBuffer)) { + if (isValidReply(inputBuffer)) + { // Reply is good, get full length uint8_t replyLen = (inputBuffer[1] & 0x0F) * 2; @@ -135,14 +155,19 @@ uint8_t *autoShiftData(uint8_t port, const uint8_t *out, const uint8_t len) { // Shift out rest of command shiftDataInOut(out + 2, inputBuffer + 3, len - 2); - if (left == 0) { + if (left == 0) + { // The whole reply was gathered ret = inputBuffer; - } else if (len + left <= BUFFER_SIZE) { + } + else if (len + left <= BUFFER_SIZE) + { // Part of reply is still missing and we have space for it shiftDataInOut(NULL, inputBuffer + len + 1, left); ret = inputBuffer; - } else { + } + else + { // Reply incomplete but not enough space provided } } @@ -150,48 +175,60 @@ uint8_t *autoShiftData(uint8_t port, const uint8_t *out, const uint8_t len) { } return ret; } -bool sendCommand(uint8_t port, const uint8_t *buf, uint8_t len) { +bool sendCommand(uint8_t port, const uint8_t *buf, uint8_t len) +{ bool ret = false; unsigned long start = millis(); - do { + do + { uint8_t *in = autoShiftData(port, buf, len); /* We can't know if we have successfully enabled analog mode until * we get out of config mode, so let's just be happy if we get a few * consecutive valid replies */ - if (in != NULL) { - if (buf == commandEnterConfig) { + if (in != NULL) + { + if (buf == commandEnterConfig) + { ret = isConfigReply(in); - } else if (buf == commandExitConfig) { + } + else if (buf == commandExitConfig) + { ret = !isConfigReply(in); } } - if (!ret) { + if (!ret) + { delay(COMMAND_RETRY_INTERVAL); } } while (!ret && millis() - start <= COMMAND_TIMEOUT); return ret; } extern unsigned long millis_at_boot; -uint8_t *tickPS2() { +uint8_t *tickPS2() +{ uint8_t *in; // PS2 guitars die if you poll them too fast - if (ps2ControllerType == PSX_GUITAR_HERO_CONTROLLER && micros() - last < 3000) { + if ((ps2ControllerType == PSX_GUITAR_HERO_CONTROLLER || ps2ControllerType == PSX_DUALSHOCK_1_CONTROLLER) && micros() - last < 3000) + { return inputBuffer; } // If this is changed to a different port, you can talk to different devices // on a multitap. Not sure how useful this is unless we make a ps2 variant // that works with the multitap, and offers four devices uint8_t port = A; - if (!initialised) { - if (!autoShiftData(port, commandPollInput, sizeof(commandPollInput))) { + if (!initialised) + { + if (!autoShiftData(port, commandPollInput, sizeof(commandPollInput))) + { initialised = false; return NULL; } - if (sendCommand(port, commandEnterConfig, sizeof(commandEnterConfig))) { + if (sendCommand(port, commandEnterConfig, sizeof(commandEnterConfig))) + { // Enable analog sticks - sendCommand(port, commandSetMode, sizeof(commandSetMode)); + sendCommand(port, commandSetMode, sizeof(commandSetMode)); // Enable pressure sensitive buttons // Some PS2 controllers are stupid and *really* need to be told to enable pressure sensitivity // for (int i = 0; i < 20; i++) { @@ -201,52 +238,82 @@ uint8_t *tickPS2() { } uint8_t *in = autoShiftData(port, commandPollInput, sizeof(commandPollInput)); - if (isDualShock2Reply(in)) { + if (isDualShock2Reply(in)) + { uint16_t buttonWord = ~(((uint16_t)in[4] << 8) | in[3]); - if (bit_check(buttonWord, PSB_PAD_LEFT)) { + if (bit_check(buttonWord, PSB_PAD_LEFT)) + { ps2ControllerType = PSX_GUITAR_HERO_CONTROLLER; - } else { + } + else + { ps2ControllerType = PSX_DUALSHOCK_2_CONTROLLER; } - } else if (isDualShockReply(in)) { + } + else if (isDualShockReply(in)) + { uint16_t buttonWord = ~(((uint16_t)in[4] << 8) | in[3]); - if (bit_check(buttonWord, PSB_PAD_LEFT)) { + if (bit_check(buttonWord, PSB_PAD_LEFT)) + { ps2ControllerType = PSX_GUITAR_HERO_CONTROLLER; - } else { + } + else + { ps2ControllerType = PSX_DUALSHOCK_1_CONTROLLER; } - } else if (isFlightStickReply(in)) { + } + else if (isFlightStickReply(in)) + { ps2ControllerType = PSX_FLIGHTSTICK; - } else if (isNegconReply(in)) { + } + else if (isNegconReply(in)) + { ps2ControllerType = PSX_NEGCON; - } else if (isJogconReply(in)) { + } + else if (isJogconReply(in)) + { ps2ControllerType = PSX_JOGCON; - } else if (isGunconReply(in)) { + } + else if (isGunconReply(in)) + { ps2ControllerType = PSX_GUNCON; - } else if (isMouseReply(in)) { + } + else if (isMouseReply(in)) + { ps2ControllerType = PSX_MOUSE; - } else if (isDigitalReply(in)) { + } + else if (isDigitalReply(in)) + { +#if DEVICE_TYPE == TAIKO + ps2ControllerType = PSX_TAIKO; +#else ps2ControllerType = PSX_DIGITAL; +#endif } initialised = true; invalidCount = 0; } // Ocassionally, the controller returns a bad packet because it isn't ready. We should ignore that instead of reinitialisng, and // We only want to reinit if we recevied several bad packets in a row. - if (initialised) { + if (initialised) + { in = autoShiftData(port, commandPollInput, sizeof(commandPollInput)); - - if (in != NULL) { + if (in != NULL) + { invalidCount = 0; - if (isConfigReply(in)) { + if (isConfigReply(in)) + { // We're stuck in config mode, try to get out sendCommand(port, commandExitConfig, sizeof(commandExitConfig)); } memcpy(inputBuffer2, inputBuffer, sizeof(inputBuffer)); last = micros(); - } else { + } + else + { invalidCount++; - if (invalidCount > 10) { + if (invalidCount > 10) + { initialised = false; } in = inputBuffer2; diff --git a/src/shared/main/shared_main.cpp b/src/shared/main/shared_main.cpp index aeca871a4..9c0164bbe 100644 --- a/src/shared/main/shared_main.cpp +++ b/src/shared/main/shared_main.cpp @@ -2,6 +2,8 @@ #include "Arduino.h" #include "accel.h" +#include "bh_drum.h" +#include "gh5_neck.h" #include "bt.h" #include "config.h" #include "controllers.h" @@ -16,37 +18,51 @@ #include "pico_slave.h" #include "pin_funcs.h" #include "ps2.h" +#include "state_translation/drums.h" #include "state_translation/pro_guitar.h" #include "state_translation/pro_keys.h" -#include "state_translation/drums.h" #include "usbhid.h" #include "util.h" #include "wii.h" #include "wt_drum.h" -#include "bh_drum.h" +#include "quadrature_encoder.pio.h" +#include "protar_neck.h" +#include "midi.hpp" +#define UP 1 << 0 +#define DOWN 1 << 1 +#define LEFT 1 << 2 +#define RIGHT 1 << 3 +static const uint8_t dpad_bindings[] = {0x08, 0x00, 0x04, 0x08, 0x06, 0x07, 0x05, 0x08, 0x02, 0x01, 0x03}; +static const uint8_t dpad_bindings_reverse[] = {UP, UP | RIGHT, RIGHT, DOWN | RIGHT, DOWN, DOWN | LEFT, LEFT, UP | LEFT}; #define DJLEFT_ADDR 0x0E #define DJRIGHT_ADDR 0x0D #define DJ_BUTTONS_PTR 0x12 #define GH5NECK_ADDR 0x0D #define CLONE_ADDR 0x10 #define CLONE_VALID_PACKET 0x52 -#define GH5NECK_BUTTONS_PTR 0x12 +#define GH5NECK_BUTTONS_PTR 0x10 #define BUFFER_SIZE_QUEUE 255 #define KEY_ERR_OVF 0x01 #define REQUIRE_LED_DEBOUNCE LED_COUNT || LED_COUNT_PERIPHERAL || LED_COUNT_STP || LED_COUNT_PERIPHERAL_STP || LED_COUNT_WS2812 || LED_COUNT_PERIPHERAL_WS2812 || HAS_LED_OUTPUT || LED_COUNT_MPR121 -struct { - union { +struct +{ + union + { signed int ltt : 6; - struct { + struct + { unsigned int ltt40 : 5; unsigned int ltt5 : 1; }; }; } ltt_t; -struct { - union { +struct +{ + union + { signed int rtt : 6; - struct { + struct + { unsigned int rtt0 : 1; unsigned int rtt21 : 2; unsigned int rtt43 : 2; @@ -54,49 +70,27 @@ struct { }; }; } rtt_t; +unsigned long lastCrkdSend; +crkd_neck_t lastCrkd; +protarneck_t lastProtar; unsigned long lastMidi = 0; Midi_Data_t midiData = {0}; -void onNote(uint8_t channel, uint8_t note, uint8_t velocity) { - // velocities are 7 bit - printf("Note ON ch=%d, note=%d, vel=%d\r\n", channel, note, velocity); - velocity = velocity << 1; - if (velocity > midiData.midiVelocitiesTemp[note]) { - midiData.midiVelocities[note] = velocity; - midiData.midiVelocitiesTemp[note] = velocity; - } - lastMidi = millis(); +MidiDevice usbMidi(true, &midiData); +MidiDevice serialMidi(false, &midiData); -} - -void offNote(uint8_t channel, uint8_t note, uint8_t velocity) { - printf("Note OFF ch=%d, note=%d, vel=%d\r\n", channel, note, velocity); - // midiData.midiVelocities[note] = 0; - // midiData.midiVelocitiesTemp[note] = 0; -} - -void onControlChange(uint8_t channel, uint8_t b1, uint8_t b2) { - // cc are 7 bit - printf("ControlChange ch=%d, b1=%d, b2=%d\r\n", channel, b1, b2); - if (b1 == MIDI_CONTROL_COMMAND_SUSTAIN_PEDAL) { - midiData.midiSustainPedal = b2 << 1; - } - if (b1 == MIDI_CONTROL_COMMAND_MOD_WHEEL) { - midiData.midiModWheel = b2 << 1; - } -} - -void onPitchBend(uint8_t channel, int pitch) { - // pitchbend is signed 14 bit - printf("PitchBend ch=%d, pitch=%d\r\n", channel, pitch); - midiData.midiPitchWheel = pitch << 2; -} +uint8_t *dj_left = lastSuccessfulTurntablePacketLeft; +uint8_t *dj_right = lastSuccessfulTurntablePacketRight; +int8_t dj_turntable_left = 0; +int8_t dj_turntable_right = 0; +bool djLeftValid = true; +bool djRightValid = true; uint8_t tmp = 0; long clone_guitar_timer = 0; long clone_guitar_ready_timer = 0; bool clone_ready = false; bool reading = false; Buffer_Report_t last_queue_report; -long last_queue = 0; +uint32_t last_queue = 0; uint8_t brightness = LED_BRIGHTNESS; uint8_t queue_size = 0; uint8_t led_tmp; @@ -132,11 +126,11 @@ long lastLed = 0; long lastSentGHLPoke = 0; long input_start = 0; long lastDebounce = 0; -long lastInputActivity = 0; // used for inactivity timeout(s) +long lastInputActivity = 0; // used for inactivity timeout(s) long lastHeartbeat = 0; long lastInactivityPulse = 0; -bool startedInactivityPulse = false; // used to ignore inputs while outputting pulse - // (for hardware wired with input and output via same pin) +bool startedInactivityPulse = false; // used to ignore inputs while outputting pulse + // (for hardware wired with input and output via same pin) uint16_t lastMpr121 = 0; bool hasTapBar = false; uint8_t ghl_sequence_number_host = 1; @@ -149,12 +143,12 @@ uint8_t lastSuccessfulClonePacket[4]; uint8_t lastSuccessfulTurntablePacketLeft[3]; uint8_t lastSuccessfulTurntablePacketRight[3]; long lastSuccessfulGHWTPacket; -bool lastGH5WasSuccessful = false; bool lastCloneWasSuccessful = false; bool lastTurntableWasSuccessfulLeft = false; bool lastTurntableWasSuccessfulRight = false; bool lastWiiWasSuccessful = false; bool lastPS2WasSuccessful = false; +bool lastCrkdWasSuccessful = false; bool overrideR2 = false; bool lastXboxOneGuide = false; bool disable_multiplexer = false; @@ -172,7 +166,7 @@ USB_Host_Data_t bt_data; uint8_t rawWt; uint8_t rawWtPeripheral; bool auth_ps4_controller_found = false; -bool seen_ps4_console = false; +bool report_requested = false; bool hasFlags = false; GipPowerMode_t powerMode; Gip_Led_On_t ledOn; @@ -222,12 +216,6 @@ uint8_t ledStateMpr121 = 0; uint8_t ledStateMpr121Select = 0; uint8_t lastLedStateMpr121 = 0; #endif -#define UP 1 << 0 -#define DOWN 1 << 1 -#define LEFT 1 << 2 -#define RIGHT 1 << 3 -static const uint8_t dpad_bindings[] = {0x08, 0x00, 0x04, 0x08, 0x06, 0x07, 0x05, 0x08, 0x02, 0x01, 0x03}; -static const uint8_t dpad_bindings_reverse[] = {UP, UP | RIGHT, RIGHT, DOWN | RIGHT, DOWN, DOWN | LEFT, LEFT, UP | LEFT}; uint8_t gh5_mapping[] = { 0x80, 0x15, 0x4D, 0x30, 0x9A, 0x99, 0x66, @@ -235,30 +223,45 @@ uint8_t gh5_mapping[] = { 0xAE, 0xAC, 0xFF, 0xFB, 0xFD, 0xF9, 0xFE, 0xFA, 0xFC, 0xF8, 0xE6, 0xE2, 0xE4, 0xE0, 0xE5, 0xE1, 0xE3, 0xDF}; -void setKey(uint8_t id, uint8_t key, USB_6KRO_Data_t *report, bool state) { - if (state) { - for (size_t i = 0; i < 6; i++) { - if (report->KeyCode[i] == key) { - return; - } - if (!report->KeyCode[i]) { - report->KeyCode[i] = key; - return; - } +void setKey(uint8_t id, uint8_t key, USB_6KRO_Data_t *report) +{ + for (size_t i = 0; i < 6; i++) + { + if (report->KeyCode[i] == key) + { + return; + } + if (!report->KeyCode[i]) + { + report->KeyCode[i] = key; + return; } - // Too many buttons - flag the overflow condition and clear all key indexes - memset(report->KeyCode, KEY_ERR_OVF, sizeof(report->KeyCode)); - return; } + // Too many buttons - flag the overflow condition and clear all key indexes + memset(report->KeyCode, KEY_ERR_OVF, sizeof(report->KeyCode)); + return; } +int new_value, delta, old_value = 0; +int last_value = -1, last_delta = -1; +PIO pio = pio1; +const uint sm = 0; +spi_inst_t *hardware; uint8_t seq = 1; -void init_main(void) { +uint32_t lastQuadPoll = 0; +void init_main(void) +{ #if !DEVICE_TYPE_IS_GAMEPAD consoleType = UNIVERSAL; #endif + +#ifdef INPUT_QUAD + pio_add_program(pio, &quadrature_encoder_program); + quadrature_encoder_program_init(pio, sm, INPUT_QUAD, 0); +#endif initPins(); twi_init(); spi_begin(); + uart_begin(); GIP_HEADER((&powerMode), GIP_POWER_MODE_DEVICE_CONFIG, true, 1); powerMode.subcommand = GIP_POWER_ON; GIP_HEADER((&ledOn), GIP_CMD_LED, true, 1); @@ -284,17 +287,30 @@ void init_main(void) { ps2_emu_init(); #endif memset(midiData.midiVelocities, 0, sizeof(midiData.midiVelocities)); -#ifdef TICK_WII + // if we have an enable line, we defer init until it goes high +#if defined(TICK_WII) initWiiOutput(); #endif + + memset(midiData.midiVelocities, 0, sizeof(midiData.midiVelocities)); + midiData.midiPitchWheel = 0; + memset(midiData.midiControlChanges, 0, sizeof(midiData.midiControlChanges)); + memset(midiData.midiFrets, 0, sizeof(midiData.midiFrets)); + memset(midiData.midiStringVelocities, 0, sizeof(midiData.midiStringVelocities)); + memset(&midiData.proGuitarData, 0, sizeof(midiData.proGuitarData)); + // default to neutral + midiData.proGuitarData.dpad = 8; } #ifdef SLAVE_TWI_PORT bool slave_initted = false; -void tick_slave() { - if (slave_initted) { +void tick_slave() +{ + if (slave_initted) + { return; } - if (!slaveInit()) { + if (!slaveInit()) + { return; } slave_initted = true; @@ -312,54 +328,89 @@ void tick_slave() { #ifdef INPUT_WT_SLAVE_NECK slaveInitWt(); #endif +#ifdef INPUT_QUAD_SLAVE + slaveInitQuad(INPUT_QUAD_SLAVE, INPUT_QUAD_RATE); +#endif } #endif -int16_t adc_i(uint8_t pin) { +int16_t adc_i(uint8_t pin) +{ int32_t ret = adc(pin); return ret - 32767; } -int16_t handle_calibration_xbox(int16_t previous, int32_t orig_val, int16_t min, int16_t max, int16_t center, int16_t deadzone) { +int16_t handle_calibration_xbox(int16_t previous, int32_t orig_val, int16_t min, int16_t max, int16_t center, int16_t deadzone, uint8_t section) +{ int32_t val = orig_val; - if (val > INT16_MAX) { + if (val > INT16_MAX) + { val = INT16_MAX; } - if (val < INT16_MIN) { + if (val < INT16_MIN) + { val = INT16_MIN; } - if (val < center) { - if ((center - val) < deadzone) { - val = 0; - } else { - val = map(val, min, center - deadzone, INT16_MIN, 0); + if (section == 0) + { + if (val < center) + { + if ((center - val) < deadzone) + { + val = 0; + } + else + { + val = map(val, min, center - deadzone, INT16_MIN, 0); + } } - - } else { - if ((val - center) < deadzone) { - val = 0; - } else { - val = map(val, center + deadzone, max, 0, INT16_MAX); + else + { + if ((val - center) < deadzone) + { + val = 0; + } + else + { + val = map(val, center + deadzone, max, 0, INT16_MAX); + } } } - if (val > INT16_MAX) { + else if (section == 1) + { + val = map(val, min, max, INT16_MIN, 0); + } + else if (section == 2) + { + val = map(val, min, max, 0, INT16_MAX); + } + if (val > INT16_MAX) + { val = INT16_MAX; } - if (val < INT16_MIN) { + if (val < INT16_MIN) + { val = INT16_MIN; } - if (abs(val) > abs(previous)) { + if (abs(val) > abs(previous)) + { return val; } return previous; } -int16_t handle_calibration_xbox_whammy(int16_t previous, uint32_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) { +int16_t handle_calibration_xbox_whammy(int16_t previous, uint32_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) +{ int32_t val = orig_val; - if (multiplier > 0) { - if ((val - min) < deadzone) { + if (multiplier > 0) + { + if ((val - min) < deadzone) + { return INT16_MIN; } - } else { - if (val > min) { + } + else + { + if (val > min) + { return INT16_MIN; } } @@ -367,93 +418,138 @@ int16_t handle_calibration_xbox_whammy(int16_t previous, uint32_t orig_val, uint val *= multiplier; val /= 512; val += INT16_MIN; - if (val > INT16_MAX) { + if (val > INT16_MAX) + { val = INT16_MAX; } - if (val < INT16_MIN) { + if (val < INT16_MIN) + { val = INT16_MIN; } - if (val > previous) { + if (val > previous) + { return val; } return previous; } -uint16_t handle_calibration_xbox_one_trigger(uint16_t previous, uint16_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) { +uint16_t handle_calibration_xbox_one_trigger(uint16_t previous, uint16_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) +{ int32_t val = orig_val; - if (multiplier > 0) { - if ((val - min) < deadzone) { + if (multiplier > 0) + { + if ((val - min) < deadzone) + { return 0; } - } else { - if (val > min) { + } + else + { + if (val > min) + { return 0; } } val -= min; val *= multiplier; val /= 512; - if (val > UINT16_MAX) { + if (val > UINT16_MAX) + { val = UINT16_MAX; } - if (val < 0) { + if (val < 0) + { val = 0; } val = val >> 6; - if (val > previous) { + if (val > previous) + { return val; } return previous; } -uint16_t handle_calibration_drum(uint16_t previous, uint16_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) { +uint16_t handle_calibration_drum(uint16_t previous, uint16_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) +{ int32_t val = orig_val; - if (multiplier > 0) { - if ((val - min) < deadzone) { + if (multiplier > 0) + { + if ((val - min) < deadzone) + { return 0; } - } else { - if (val > min) { + } + else + { + if (val > min) + { return 0; } } val -= min; val *= multiplier; val /= 512; - if (val > UINT16_MAX) { + if (val > UINT16_MAX) + { val = UINT16_MAX; } - if (val < 0) { + if (val < 0) + { val = 0; } - if (val > previous) { + if (val > previous) + { return val; } return previous; } -uint8_t handle_calibration_ps3(uint8_t previous, int32_t orig_val, int16_t min, int16_t max, int16_t center, int16_t deadzone) { - int8_t ret = handle_calibration_xbox((previous - PS3_STICK_CENTER) << 8, orig_val, min, max, center, deadzone) >> 8; +uint8_t handle_calibration_ps3(uint8_t previous, int32_t orig_val, int16_t min, int16_t max, int16_t center, int16_t deadzone, uint8_t section) +{ + int8_t ret = handle_calibration_xbox((previous - PS3_STICK_CENTER) << 8, orig_val, min, max, center, deadzone, section) >> 8; return (uint8_t)(ret + PS3_STICK_CENTER); } +uint8_t handle_calibration_ps4_xb1_tilt(uint8_t previous, int32_t orig_val, int16_t min, int16_t max, int16_t center, int16_t deadzone) +{ + int16_t ret = abs(handle_calibration_xbox(previous << 7, orig_val, min, max, center, deadzone, 0)) >> 7; + if (ret > 255) + { + ret = 255; + } + if (ret < 0) + { + ret = 0; + } + return (uint8_t)(ret); +} -int8_t handle_calibration_mouse(int8_t previous, int32_t orig_val, int16_t min, int16_t max, int16_t center, int16_t deadzone) { - return handle_calibration_xbox(previous << 8, orig_val, min, max, center, deadzone) >> 8; +int8_t handle_calibration_mouse(int8_t previous, int32_t orig_val, int16_t min, int16_t max, int16_t center, int16_t deadzone) +{ + return handle_calibration_xbox(previous << 8, orig_val, min, max, center, deadzone, 0) >> 8; } -uint8_t handle_calibration_ps3_360_trigger(uint8_t previous, uint16_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) { +uint8_t handle_calibration_ps3_360_trigger(uint8_t previous, uint16_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) +{ return handle_calibration_xbox_one_trigger(previous << 2, orig_val, min, multiplier, deadzone) >> 2; } -uint16_t handle_calibration_ps3_accel(uint16_t previous, int32_t orig_val, int16_t min, int16_t max, int16_t center, uint16_t deadzone) { +uint16_t handle_calibration_ps3_accel(uint16_t previous, int32_t orig_val, int16_t min, int16_t max, int16_t center, uint16_t deadzone) +{ #if DEVICE_TYPE_IS_GUITAR || DEVICE_TYPE_IS_LIVE_GUITAR // For whatever reason, the acceleration for guitars swings between -128 to 128, not -512 to 512 // Also, the game is looking for the value going negative, not positive - int16_t ret = (-(handle_calibration_xbox(-((previous - PS3_ACCEL_CENTER) << 8), orig_val, min, max, center, deadzone) >> 8)); + int16_t ret = (-(handle_calibration_xbox(-((previous - PS3_ACCEL_CENTER) << 8), orig_val, min, max, center, deadzone, 0) >> 8)); #else - int16_t ret = handle_calibration_xbox((previous - PS3_ACCEL_CENTER) << 6, orig_val, min, max, center, deadzone) >> 6; + int16_t ret = handle_calibration_xbox((previous - PS3_ACCEL_CENTER) << 6, orig_val, min, max, center, deadzone, 0) >> 6; #endif return PS3_ACCEL_CENTER + ret; } + +uint8_t handle_calibration_arcade_accel(uint16_t previous, int32_t orig_val, int16_t min, int16_t max, int16_t center, uint16_t deadzone) +{ + int8_t ret = handle_calibration_xbox((previous) << 8, orig_val, min, max, center, deadzone, 0) >> 8; + return (uint8_t)(ret); +} long last_zero = 0; -uint8_t handle_calibration_ps3_whammy(uint8_t previous, uint16_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) { +uint8_t handle_calibration_ps3_whammy(uint8_t previous, uint16_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) +{ #if DEVICE_TYPE == ROCK_BAND_GUITAR // RB whammy is full range return handle_calibration_ps3_360_trigger(previous, orig_val, min, multiplier, deadzone); @@ -463,102 +559,119 @@ uint8_t handle_calibration_ps3_whammy(uint8_t previous, uint16_t orig_val, uint3 return ret + PS3_STICK_CENTER; #endif } -uint8_t handle_calibration_ps2_whammy(uint8_t previous, uint16_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) { +uint8_t handle_calibration_ps2_whammy(uint8_t previous, uint16_t orig_val, uint32_t min, int16_t multiplier, uint16_t deadzone) +{ // GH whammy ignores the negative half of the axis, so shift to get between 0 and 127, then subtract from center uint8_t ret = handle_calibration_ps3_360_trigger((0x7f - previous) << 1, orig_val, min, multiplier, deadzone) >> 1; return 0x7f - ret; } -uint8_t handle_calibration_turntable_ps3(uint8_t previous, int16_t orig_val, uint8_t multiplier) { +uint8_t handle_calibration_turntable_ps3(uint8_t previous, int16_t orig_val, uint8_t multiplier) +{ int32_t val = (orig_val * multiplier) >> 8; - if (val > INT8_MAX) { + if (val > INT8_MAX) + { val = INT8_MAX; } - if (val < INT8_MIN) { + if (val < INT8_MIN) + { val = INT8_MIN; } // previous is uint, convert to int to test - if (abs(val) > abs((int)previous - PS3_STICK_CENTER)) { + if (abs(val) > abs((int)previous - PS3_STICK_CENTER)) + { // ps3 wants uint, convert to uint return (uint8_t)(val + PS3_STICK_CENTER); } return previous; } -int16_t handle_calibration_turntable_360(int16_t previous, int16_t orig_val, uint8_t multiplier) { - if (consoleType == WINDOWS && WINDOWS_TURNTABLE_FULLRANGE) { +int16_t handle_calibration_turntable_360(int16_t previous, int16_t orig_val, uint8_t multiplier) +{ + if (consoleType == WINDOWS && WINDOWS_TURNTABLE_FULLRANGE) + { int32_t val = (orig_val * multiplier); - if (val > INT16_MAX) { + if (val > INT16_MAX) + { val = INT16_MAX; } - if (val < INT16_MIN) { + if (val < INT16_MIN) + { val = INT16_MIN; } - if (abs(val) > abs(previous)) { + if (abs(val) > abs(previous)) + { return (int16_t)val; } return previous; } int32_t val = (orig_val * multiplier) >> 8; - if (val > 128) { + if (val > 128) + { val = 128; } - if (val < -128) { + if (val < -128) + { val = -128; } - if (abs(val) > abs(previous)) { + if (abs(val) > abs(previous)) + { return (int16_t)val; } return previous; } uint16_t descriptor_index = 0; -uint8_t tick_xbox_one() { +long reset_after_360 = 0; +uint8_t tick_xbox_one() +{ uint32_t serial = micros(); - switch (xbox_one_state) { - case Announce: - descriptor_index = 0; - xbox_one_state = WaitingDesc1; - memcpy(&combined_report, announce, sizeof(announce)); - memcpy(&combined_report.raw[7], &serial, 3); - return sizeof(announce); - case IdentDesc1: - xbox_one_state = WaitingDesc; - descriptor_index += 64; - memcpy(&combined_report, xb1_descriptor, 64); - return 64; - case IdentDesc: { - uint16_t len = sizeof(xb1_descriptor) - descriptor_index; - if (len > 64) { - len = 64; - } else { - xbox_one_state = WaitingDescEnd; - } - memcpy(&combined_report, xb1_descriptor + descriptor_index, len); - descriptor_index += len; - return len; - } - case IdentDescEnd: { - xbox_one_state = Auth; - memcpy(&combined_report, xb1_descriptor_end, sizeof(xb1_descriptor_end)); - return sizeof(xb1_descriptor_end); - } - case Auth: - if (data_from_controller_size) { - uint8_t size = data_from_controller_size; - data_from_controller_size = 0; - memcpy(&combined_report, data_from_controller, size); - return size; - } - return 0; - case Ready: - return 0; - default: - return 0; + switch (xbox_one_state) + { + case Announce: + descriptor_index = 0; + xbox_one_state = WaitingDesc1; + memcpy(&combined_report, announce, sizeof(announce)); + memcpy(&combined_report.raw[7], &serial, 3); + return sizeof(announce); + case IdentDesc1: + xbox_one_state = WaitingDesc; + descriptor_index += 64; + memcpy(&combined_report, xb1_descriptor, 64); + return 64; + case IdentDesc: + { + uint16_t len = sizeof(xb1_descriptor) - descriptor_index; + if (len > 64) + { + len = 64; + } + else + { + xbox_one_state = WaitingDescEnd; + } + memcpy(&combined_report, xb1_descriptor + descriptor_index, len); + descriptor_index += len; + return len; + } + case IdentDescEnd: + { + xbox_one_state = Auth; + memcpy(&combined_report, xb1_descriptor_end, sizeof(xb1_descriptor_end)); + return sizeof(xb1_descriptor_end); + } + case Auth: + return 0; + case Ready: + return 0; + default: + return 0; } } -static uint8_t xinput_rb_velocity_positive(int16_t velocity) { +static uint8_t xinput_rb_velocity_positive(int16_t velocity) +{ return (uint8_t)(255 - (uint8_t)(velocity >> 7)); } -static uint8_t xinput_rb_velocity_negative(int16_t velocity) { +static uint8_t xinput_rb_velocity_negative(int16_t velocity) +{ if (velocity == 0) return 255; @@ -566,22 +679,237 @@ static uint8_t xinput_rb_velocity_negative(int16_t velocity) { } long lastTick; uint8_t keyboard_report = 0; -void convert_report(const uint8_t *data, uint8_t len, USB_Device_Type_t device_type, USB_Host_Data_t *usb_host_data) { - switch (device_type.console_type) { - case STADIA: { - Stadia_Data_t *report = (Stadia_Data_t *)data; - uint8_t dpad = report->dpad >= 0x08 ? 0 : dpad_bindings_reverse[report->dpad]; - asm volatile("" :: - : "memory"); - bool up = dpad & UP; - bool left = dpad & LEFT; - bool down = dpad & DOWN; - bool right = dpad & RIGHT; +void convert_report(const uint8_t *data, uint8_t len, USB_Device_Type_t device_type, USB_Host_Data_t *usb_host_data) +{ + if (!len) + { + return; + } + switch (device_type.console_type) + { + case STADIA: + { + Stadia_Data_t *report = (Stadia_Data_t *)data; + uint8_t dpad = report->dpad >= 0x08 ? 0 : dpad_bindings_reverse[report->dpad]; + asm volatile("" :: + : "memory"); + bool up = dpad & UP; + bool left = dpad & LEFT; + bool down = dpad & DOWN; + bool right = dpad & RIGHT; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->capture |= report->capture; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + if (report->leftTrigger) + { + usb_host_data->leftTrigger = report->leftTrigger << 8; + } + if (report->rightTrigger) + { + usb_host_data->rightTrigger = report->rightTrigger << 8; + } + if (report->leftStickX != PS3_STICK_CENTER) + { + usb_host_data->leftStickX = (report->leftStickX - PS3_STICK_CENTER) << 8; + } + if (report->leftStickY != PS3_STICK_CENTER) + { + usb_host_data->leftStickY = (((UINT8_MAX - report->leftStickY) - PS3_STICK_CENTER)) << 8; + } + if (report->rightStickX != PS3_STICK_CENTER) + { + usb_host_data->rightStickX = (report->rightStickX - PS3_STICK_CENTER) << 8; + } + if (report->rightStickY != PS3_STICK_CENTER) + { + usb_host_data->rightStickY = (((UINT8_MAX - report->rightStickY) - PS3_STICK_CENTER)) << 8; + } + } + case STREAM_DECK: + { + uint8_t offset = 1; + switch (device_type.sub_type) + { + case STREAM_DECK_XL: + case STREAM_DECK_MK2: + case STREAM_DECK_NEO: + case STREAM_DECK_V2: + case STREAM_DECK_XLV2: + case STREAM_DECK_PEDAL: + case STREAM_DECK_PLUS: + offset = 4; + break; + } + for (uint8_t i = 0; i + offset < len && i < 16; i++) + { + bit_write(data[i + offset], usb_host_data->genericButtons, i); + } + break; + } + case KEYBOARD: + { + USB_6KRO_Boot_Data_t *report = (USB_6KRO_Boot_Data_t *)data; + usb_host_data->keyboard.leftCtrl = report->leftCtrl; + usb_host_data->keyboard.leftShift = report->leftShift; + usb_host_data->keyboard.leftAlt = report->leftAlt; + usb_host_data->keyboard.lWin = report->lWin; + usb_host_data->keyboard.rightCtrl = report->rightCtrl; + usb_host_data->keyboard.rightShift = report->rightShift; + usb_host_data->keyboard.rightAlt = report->rightAlt; + usb_host_data->keyboard.rWin = report->rWin; + uint8_t *keyData = usb_host_data->keyboard.raw; + for (uint8_t i = 0; i < SIMULTANEOUS_KEYS; i++) + { + uint8_t keycode = report->KeyCode[i]; + // F24 is the last supported key in our nkro report + if (keycode && keycode <= KEYCODE_F24) + { + bit_set(keyData[keycode >> 3], keycode & 7); + } + } + break; + } + case MOUSE: + { + USB_Mouse_Boot_Data_t *report = (USB_Mouse_Boot_Data_t *)data; + memcpy(&usb_host_data->mouse, report, sizeof(USB_Mouse_Boot_Data_t)); + break; + } + case GENERIC: + { + USB_Host_Data_t *report = (USB_Host_Data_t *)data; + usb_host_data->genericAxisX = report->genericAxisX; + usb_host_data->genericAxisY = report->genericAxisY; + usb_host_data->genericAxisZ = report->genericAxisZ; + usb_host_data->genericAxisRx = report->genericAxisRx; + usb_host_data->genericAxisRy = report->genericAxisRy; + usb_host_data->genericAxisRz = report->genericAxisRz; + usb_host_data->genericAxisSlider = report->genericAxisSlider; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + usb_host_data->genericButtons |= report->genericButtons; + break; + } + case RAPHNET: + { + switch (device_type.sub_type) + { + case GAMEPAD: + { + RaphnetGamepad_Data_t *report = (RaphnetGamepad_Data_t *)data; + usb_host_data->leftStickX = report->leftJoyX - 16000; + usb_host_data->leftStickY = report->leftJoyY - 16000; + usb_host_data->rightStickX = report->rightJoyX - 16000; + usb_host_data->rightStickY = report->rightJoyY - 16000; + usb_host_data->leftTrigger = report->leftTrigger; + usb_host_data->rightTrigger = report->rightTrigger; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->start |= report->start; + usb_host_data->back |= report->select; + usb_host_data->guide |= report->home; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->dpadLeft |= report->left; + usb_host_data->dpadRight |= report->right; + usb_host_data->dpadUp |= report->up; + usb_host_data->dpadDown |= report->down; + break; + } + case GUITAR_HERO_GUITAR: + { + RaphnetGuitar_Data_t *report = (RaphnetGuitar_Data_t *)data; + usb_host_data->leftStickX = report->joyX - 16000; + usb_host_data->leftStickY = report->joyY - 16000; + usb_host_data->whammy = report->whammy >> 8; + usb_host_data->start = report->plus; + usb_host_data->back = report->minus; + usb_host_data->green |= report->green; + usb_host_data->red |= report->red; + usb_host_data->yellow |= report->yellow; + usb_host_data->blue |= report->blue; + usb_host_data->orange |= report->orange; + usb_host_data->a |= report->green; + usb_host_data->b |= report->red; + usb_host_data->y |= report->yellow; + usb_host_data->x |= report->blue; + usb_host_data->leftShoulder |= report->orange; + usb_host_data->dpadUp |= report->up; + usb_host_data->dpadDown |= report->down; + break; + } + case GUITAR_HERO_DRUMS: + { + RaphnetDrum_Data_t *report = (RaphnetDrum_Data_t *)data; + usb_host_data->leftStickX = report->joyX - 16000; + usb_host_data->leftStickY = report->joyY - 16000; + usb_host_data->start = report->plus; + usb_host_data->back = report->minus; + usb_host_data->green |= report->green; + usb_host_data->red |= report->red; + usb_host_data->yellow |= report->yellow; + usb_host_data->blue |= report->blue; + usb_host_data->orange |= report->orange; + // TODO: figure out kick mappings for raphnet + // usb_host_data->kick1 |= report->kick1; + usb_host_data->a |= report->green; + usb_host_data->b |= report->red; + usb_host_data->y |= report->yellow; + usb_host_data->x |= report->blue; + usb_host_data->leftShoulder |= report->orange; + break; + } + } + break; + } + case SANTROLLER: + { + PCGamepad_Data_t *report = (PCGamepad_Data_t *)data; + uint8_t dpad = report->dpad >= 0x08 ? 0 : dpad_bindings_reverse[report->dpad]; + asm volatile("" :: + : "memory"); + bool up = dpad & UP; + bool left = dpad & LEFT; + bool down = dpad & DOWN; + bool right = dpad & RIGHT; + switch (device_type.sub_type) + { + case GAMEPAD: + case DANCE_PAD: + case STAGE_KIT: + { + PCGamepad_Data_t *report = (PCGamepad_Data_t *)data; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; usb_host_data->a |= report->a; usb_host_data->b |= report->b; usb_host_data->x |= report->x; usb_host_data->y |= report->y; - usb_host_data->capture |= report->capture; usb_host_data->leftShoulder |= report->leftShoulder; usb_host_data->rightShoulder |= report->rightShoulder; usb_host_data->back |= report->back; @@ -593,1560 +921,1867 @@ void convert_report(const uint8_t *data, uint8_t len, USB_Device_Type_t device_t usb_host_data->dpadRight |= right; usb_host_data->dpadUp |= up; usb_host_data->dpadDown |= down; - if (report->leftTrigger) { + if (report->leftTrigger) + { usb_host_data->leftTrigger = report->leftTrigger << 8; } - if (report->rightTrigger) { + if (report->rightTrigger) + { usb_host_data->rightTrigger = report->rightTrigger << 8; } - if (report->leftStickX != PS3_STICK_CENTER) { + if (report->leftStickX != PS3_STICK_CENTER) + { usb_host_data->leftStickX = (report->leftStickX - PS3_STICK_CENTER) << 8; } - if (report->leftStickY != PS3_STICK_CENTER) { + if (report->leftStickY != PS3_STICK_CENTER) + { usb_host_data->leftStickY = (((UINT8_MAX - report->leftStickY) - PS3_STICK_CENTER)) << 8; } - if (report->rightStickX != PS3_STICK_CENTER) { + if (report->rightStickX != PS3_STICK_CENTER) + { usb_host_data->rightStickX = (report->rightStickX - PS3_STICK_CENTER) << 8; } - if (report->rightStickY != PS3_STICK_CENTER) { + if (report->rightStickY != PS3_STICK_CENTER) + { usb_host_data->rightStickY = (((UINT8_MAX - report->rightStickY) - PS3_STICK_CENTER)) << 8; } + break; } - case STREAM_DECK: { - uint8_t offset = 1; - switch (device_type.sub_type) { - case STREAM_DECK_XL: - case STREAM_DECK_MK2: - case STREAM_DECK_NEO: - case STREAM_DECK_V2: - case STREAM_DECK_XLV2: - case STREAM_DECK_PEDAL: - case STREAM_DECK_PLUS: - offset = 4; - break; - } - for (uint8_t i = 0; i + offset < len && i < 16; i++) { - bit_write(data[i + offset], usb_host_data->genericButtons, i); - } - break; - } - case KEYBOARD: { - USB_6KRO_Boot_Data_t *report = (USB_6KRO_Boot_Data_t *)data; - usb_host_data->keyboard.leftCtrl = report->leftCtrl; - usb_host_data->keyboard.leftShift = report->leftShift; - usb_host_data->keyboard.leftAlt = report->leftAlt; - usb_host_data->keyboard.lWin = report->lWin; - usb_host_data->keyboard.rightCtrl = report->rightCtrl; - usb_host_data->keyboard.rightShift = report->rightShift; - usb_host_data->keyboard.rightAlt = report->rightAlt; - usb_host_data->keyboard.rWin = report->rWin; - uint8_t *keyData = usb_host_data->keyboard.raw; - for (uint8_t i = 0; i < SIMULTANEOUS_KEYS; i++) { - uint8_t keycode = report->KeyCode[i]; - // F24 is the last supported key in our nkro report - if (keycode && keycode <= KEYCODE_F24) { - bit_set(keyData[keycode >> 3], keycode & 7); - } + case GUITAR_HERO_GUITAR: + { + PCGuitarHeroGuitar_Data_t *report = (PCGuitarHeroGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + if (report->tilt != PS3_STICK_CENTER) + { + usb_host_data->tilt = (report->tilt - PS3_STICK_CENTER) << 8; + } + if (report->whammy) + { + usb_host_data->whammy = report->whammy; + } + if (report->slider != PS3_STICK_CENTER) + { + usb_host_data->slider = report->slider; } break; } - case MOUSE: { - USB_Mouse_Boot_Data_t *report = (USB_Mouse_Boot_Data_t *)data; - memcpy(&usb_host_data->mouse, report, sizeof(USB_Mouse_Boot_Data_t)); + case ROCK_BAND_GUITAR: + { + PCRockBandGuitar_Data_t *report = (PCRockBandGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + if (report->tilt != PS3_STICK_CENTER) + { + usb_host_data->tilt = (report->tilt - PS3_STICK_CENTER) << 8; + } + usb_host_data->soloGreen |= report->soloGreen; + usb_host_data->soloRed |= report->soloRed; + usb_host_data->soloYellow |= report->soloYellow; + usb_host_data->soloBlue |= report->soloBlue; + usb_host_data->soloOrange |= report->soloOrange; + + if (report->whammy) + { + usb_host_data->whammy = report->whammy; + } + if (report->pickup) + { + usb_host_data->pickup = report->pickup; + } break; } - case GENERIC: { - USB_Host_Data_t *report = (USB_Host_Data_t *)data; - usb_host_data->genericAxisX = report->genericAxisX; - usb_host_data->genericAxisY = report->genericAxisY; - usb_host_data->genericAxisZ = report->genericAxisZ; - usb_host_data->genericAxisRx = report->genericAxisRx; - usb_host_data->genericAxisRy = report->genericAxisRy; - usb_host_data->genericAxisRz = report->genericAxisRz; - usb_host_data->genericAxisSlider = report->genericAxisSlider; - usb_host_data->dpadLeft |= report->dpadLeft; - usb_host_data->dpadRight |= report->dpadRight; - usb_host_data->dpadUp |= report->dpadUp; - usb_host_data->dpadDown |= report->dpadDown; - usb_host_data->genericButtons |= report->genericButtons; - break; - } - case RAPHNET: { - switch (device_type.sub_type) { - case GAMEPAD: { - RaphnetGamepad_Data_t *report = (RaphnetGamepad_Data_t *)data; - usb_host_data->leftStickX = report->leftJoyX - 16000; - usb_host_data->leftStickY = report->leftJoyY - 16000; - usb_host_data->rightStickX = report->rightJoyX - 16000; - usb_host_data->rightStickY = report->rightJoyY - 16000; - usb_host_data->leftTrigger = report->leftTrigger; - usb_host_data->rightTrigger = report->rightTrigger; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->start |= report->start; - usb_host_data->back |= report->select; - usb_host_data->guide |= report->home; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->dpadLeft |= report->left; - usb_host_data->dpadRight |= report->right; - usb_host_data->dpadUp |= report->up; - usb_host_data->dpadDown |= report->down; - break; - } - case GUITAR_HERO_GUITAR: { - RaphnetGuitar_Data_t *report = (RaphnetGuitar_Data_t *)data; - usb_host_data->leftStickX = report->joyX - 16000; - usb_host_data->leftStickY = report->joyY - 16000; - usb_host_data->whammy = report->whammy >> 8; - usb_host_data->start = report->plus; - usb_host_data->back = report->minus; - usb_host_data->green |= report->green; - usb_host_data->red |= report->red; - usb_host_data->yellow |= report->yellow; - usb_host_data->blue |= report->blue; - usb_host_data->orange |= report->orange; - usb_host_data->a |= report->green; - usb_host_data->b |= report->red; - usb_host_data->y |= report->yellow; - usb_host_data->x |= report->blue; - usb_host_data->leftShoulder |= report->orange; - usb_host_data->dpadUp |= report->up; - usb_host_data->dpadDown |= report->down; - break; - } - case GUITAR_HERO_DRUMS: { - RaphnetDrum_Data_t *report = (RaphnetDrum_Data_t *)data; - usb_host_data->leftStickX = report->joyX - 16000; - usb_host_data->leftStickY = report->joyY - 16000; - usb_host_data->start = report->plus; - usb_host_data->back = report->minus; - usb_host_data->green |= report->green; - usb_host_data->red |= report->red; - usb_host_data->yellow |= report->yellow; - usb_host_data->blue |= report->blue; - usb_host_data->orange |= report->orange; - // TODO: figure out kick mappings for raphnet - // usb_host_data->kick1 |= report->kick1; - usb_host_data->a |= report->green; - usb_host_data->b |= report->red; - usb_host_data->y |= report->yellow; - usb_host_data->x |= report->blue; - usb_host_data->leftShoulder |= report->orange; - break; - } + case GUITAR_HERO_DRUMS: + { + PCGuitarHeroDrums_Data_t *report = (PCGuitarHeroDrums_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->rightShoulder; + SET_GH_PADS(); + break; + } + case ROCK_BAND_DRUMS: + { + PCRockBandDrums_Data_t *report = (PCRockBandDrums_Data_t *)data; + if (!report->padFlag && !report->cymbalFlag) + { + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + } + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + bool kick1 = report->leftShoulder; + bool kick2 = report->rightShoulder; + if (report->yellowVelocity) + { + onNote(10, RB_MIDI_NOTE_YELLOW, report->yellowVelocity >> 1); + } + if (report->blueVelocity) + { + onNote(10, RB_MIDI_NOTE_BLUE, report->blueVelocity >> 1); + } + + if (report->redVelocity) + { + onNote(10, RB_MIDI_NOTE_RED, report->redVelocity >> 1); + } + + if (report->greenVelocity) + { + onNote(10, RB_MIDI_NOTE_GREEN, report->greenVelocity >> 1); + } + if (report->blueCymbalVelocity) + { + onNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, report->blueCymbalVelocity >> 1); + } + if (report->yellowCymbalVelocity) + { + onNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, report->yellowCymbalVelocity >> 1); + } + + if (report->greenCymbalVelocity) + { + onNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, report->greenCymbalVelocity >> 1); + } + if (kick1) + { + onNote(10, RB_MIDI_NOTE_KICK, 0x7F); + } + if (kick2) + { + onNote(10, RB_MIDI_NOTE_KICK2, 0x7F); } break; } - case SANTROLLER: { - PCGamepad_Data_t *report = (PCGamepad_Data_t *)data; - uint8_t dpad = report->dpad >= 0x08 ? 0 : dpad_bindings_reverse[report->dpad]; - asm volatile("" :: - : "memory"); - bool up = dpad & UP; - bool left = dpad & LEFT; - bool down = dpad & DOWN; - bool right = dpad & RIGHT; - switch (device_type.sub_type) { - case GAMEPAD: - case DANCE_PAD: - case STAGE_KIT: { - PCGamepad_Data_t *report = (PCGamepad_Data_t *)data; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->rightThumbClick |= report->rightThumbClick; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - if (report->leftTrigger) { - usb_host_data->leftTrigger = report->leftTrigger << 8; - } - if (report->rightTrigger) { - usb_host_data->rightTrigger = report->rightTrigger << 8; - } - if (report->leftStickX != PS3_STICK_CENTER) { - usb_host_data->leftStickX = (report->leftStickX - PS3_STICK_CENTER) << 8; - } - if (report->leftStickY != PS3_STICK_CENTER) { - usb_host_data->leftStickY = (((UINT8_MAX - report->leftStickY) - PS3_STICK_CENTER)) << 8; - } - if (report->rightStickX != PS3_STICK_CENTER) { - usb_host_data->rightStickX = (report->rightStickX - PS3_STICK_CENTER) << 8; - } - if (report->rightStickY != PS3_STICK_CENTER) { - usb_host_data->rightStickY = (((UINT8_MAX - report->rightStickY) - PS3_STICK_CENTER)) << 8; - } - break; - } - case GUITAR_HERO_GUITAR: { - PCGuitarHeroGuitar_Data_t *report = (PCGuitarHeroGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - if (report->tilt != PS3_STICK_CENTER) { - usb_host_data->tilt = (report->tilt - PS3_STICK_CENTER) << 8; - } - if (report->whammy) { - usb_host_data->whammy = report->whammy; - } - usb_host_data->slider = report->slider; - break; - } - case ROCK_BAND_GUITAR: { - PCRockBandGuitar_Data_t *report = (PCRockBandGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - if (report->tilt != PS3_STICK_CENTER) { - usb_host_data->tilt = (report->tilt - PS3_STICK_CENTER) << 8; - } - usb_host_data->soloGreen |= report->soloGreen; - usb_host_data->soloRed |= report->soloRed; - usb_host_data->soloYellow |= report->soloYellow; - usb_host_data->soloBlue |= report->soloBlue; - usb_host_data->soloOrange |= report->soloOrange; - - if (report->whammy) { - usb_host_data->whammy = report->whammy; - } - if (report->pickup) { - usb_host_data->pickup = report->pickup; - } - break; - } - case GUITAR_HERO_DRUMS: { - PCGuitarHeroDrums_Data_t *report = (PCGuitarHeroDrums_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->rightShoulder; - SET_GH_PADS(); - break; - } - case ROCK_BAND_DRUMS: { - PCRockBandDrums_Data_t *report = (PCRockBandDrums_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - uint8_t redVelocity = report->redVelocity; - uint8_t greenVelocity = report->greenVelocity; - uint8_t yellowVelocity = report->yellowVelocity; - uint8_t blueVelocity = report->blueVelocity; - bool kick1 = report->leftShoulder; - bool kick2 = report->rightShoulder; - SET_RB_PADS(); - break; + case LIVE_GUITAR: + { + PCGHLGuitar_Data_t *report = (PCGHLGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + if (report->tilt != PS3_STICK_CENTER) + { + usb_host_data->tilt = (report->tilt - PS3_STICK_CENTER) << 8; + } + if (report->whammy) + { + usb_host_data->whammy = report->whammy; + } + break; + } + case DJ_HERO_TURNTABLE: + { + PCTurntable_Data_t *report = (PCTurntable_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->leftBlue |= report->leftBlue; + usb_host_data->leftRed |= report->leftRed; + usb_host_data->leftGreen |= report->leftGreen; + usb_host_data->rightBlue |= report->rightBlue; + usb_host_data->rightRed |= report->rightRed; + usb_host_data->rightGreen |= report->rightGreen; + if (report->effectsKnob != PS3_ACCEL_CENTER) + { + usb_host_data->effectsKnob = (report->effectsKnob - PS3_ACCEL_CENTER) << 6; + } + if (report->crossfader != PS3_ACCEL_CENTER) + { + usb_host_data->crossfader = (report->crossfader - PS3_ACCEL_CENTER) << 6; + } + if (report->leftTableVelocity != PS3_STICK_CENTER) + { + usb_host_data->leftTableVelocity = (report->leftTableVelocity - PS3_STICK_CENTER) << 8; + } + if (report->rightTableVelocity != PS3_STICK_CENTER) + { + usb_host_data->rightTableVelocity = (report->rightTableVelocity - PS3_STICK_CENTER) << 8; + } + break; + } + case ROCK_BAND_PRO_KEYS: + { + PCRockBandProKeyboard_Data_t *report = (PCRockBandProKeyboard_Data_t *)data; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + TRANSLATE_PRO_KEYS; + break; + } + case ROCK_BAND_PRO_GUITAR_SQUIRE: + case ROCK_BAND_PRO_GUITAR_MUSTANG: + { + PCRockBandProGuitar_Data_t *report = (PCRockBandProGuitar_Data_t *)data; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + TRANSLATE_PRO_GUITAR; + break; + } + } + break; + } + case PS3: + { + PS3Dpad_Data_t *report = (PS3Dpad_Data_t *)data; + uint8_t dpad = report->dpad >= 0x08 ? 0 : dpad_bindings_reverse[report->dpad]; + asm volatile("" :: + : "memory"); + bool up = dpad & UP; + bool left = dpad & LEFT; + bool down = dpad & DOWN; + bool right = dpad & RIGHT; + switch (device_type.sub_type) + { + case GAMEPAD: + { + PS3Gamepad_Data_t *report = (PS3Gamepad_Data_t *)data; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + if (report->leftTrigger) + { + usb_host_data->leftTrigger = report->leftTrigger << 8; + } + if (report->rightTrigger) + { + usb_host_data->rightTrigger = report->rightTrigger << 8; + } + if (report->leftStickX != PS3_STICK_CENTER) + { + usb_host_data->leftStickX = (report->leftStickX - PS3_STICK_CENTER) << 8; + } + if (report->leftStickY != PS3_STICK_CENTER) + { + usb_host_data->leftStickY = (((UINT8_MAX - report->leftStickY) - PS3_STICK_CENTER)) << 8; + } + if (report->rightStickX != PS3_STICK_CENTER) + { + usb_host_data->rightStickX = (report->rightStickX - PS3_STICK_CENTER) << 8; + } + if (report->rightStickY != PS3_STICK_CENTER) + { + usb_host_data->rightStickY = (((UINT8_MAX - report->rightStickY) - PS3_STICK_CENTER)) << 8; + } + if (report->pressureDpadUp) + { + usb_host_data->pressureDpadUp = report->pressureDpadUp; + } + if (report->pressureDpadRight) + { + usb_host_data->pressureDpadRight = report->pressureDpadRight; + } + if (report->pressureDpadDown) + { + usb_host_data->pressureDpadDown = report->pressureDpadDown; + } + if (report->pressureDpadLeft) + { + usb_host_data->pressureDpadLeft = report->pressureDpadLeft; + } + if (report->pressureL1) + { + usb_host_data->pressureL1 = report->pressureL1; + } + if (report->pressureR1) + { + usb_host_data->pressureR1 = report->pressureR1; + } + if (report->pressureTriangle) + { + usb_host_data->pressureTriangle = report->pressureTriangle; + } + if (report->pressureCircle) + { + usb_host_data->pressureCircle = report->pressureCircle; + } + if (report->pressureCross) + { + usb_host_data->pressureCross = report->pressureCross; + } + if (report->pressureSquare) + { + usb_host_data->pressureSquare = report->pressureSquare; + } + break; + } + + case ROCK_BAND_PRO_KEYS: + { + PS3RockBandProKeyboard_Data_t *report = (PS3RockBandProKeyboard_Data_t *)data; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + TRANSLATE_PRO_KEYS; + break; + } + case ROCK_BAND_GUITAR: + { + PS3RockBandGuitar_Data_t *report = (PS3RockBandGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + if (report->tilt) + { + usb_host_data->tilt = INT16_MAX; + } + if (report->solo) + { + usb_host_data->soloGreen |= report->a; + usb_host_data->soloRed |= report->b; + usb_host_data->soloYellow |= report->y; + usb_host_data->soloBlue |= report->x; + usb_host_data->soloOrange |= report->leftShoulder; + } + // whammy + pickup resets to a neutral state when not in use + // so we opt to store the last known state and use that when in neutral + if (device_type.whammy) + { + usb_host_data->whammy = device_type.whammy; + } + if (device_type.pickup) + { + usb_host_data->pickup = device_type.pickup; + } + break; + } + case GUITAR_HERO_GUITAR_WT: + case GUITAR_HERO_GUITAR: + { + PS3GuitarHeroGuitar_Data_t *report = (PS3GuitarHeroGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + if (report->tilt != PS3_ACCEL_CENTER) + { + usb_host_data->tilt = (report->tilt - PS3_ACCEL_CENTER) << 8; + } + if (report->whammy) + { + usb_host_data->whammy = (report->whammy - PS3_STICK_CENTER) << 1; + } + // Detect GH5 vs WT. Wait for a neutral input, then use that to detect instrument type + if (device_type.sub_type == GUITAR_HERO_GUITAR_WT) + { + // Its WT, convert to GH5 + if (report->slider <= 0x2F) + { + usb_host_data->slider = 0x15; + } + else if (report->slider <= 0x3F) + { + usb_host_data->slider = 0x30; + } + else if (report->slider <= 0x5F) + { + usb_host_data->slider = 0x4D; + } + else if (report->slider <= 0x6F) + { + usb_host_data->slider = 0x66; + } + else if (report->slider <= 0x8F) + { + usb_host_data->slider = 0x80; + } + else if (report->slider <= 0x9F) + { + usb_host_data->slider = 0x9A; + } + else if (report->slider <= 0xAF) + { + usb_host_data->slider = 0xAF; + } + else if (report->slider <= 0xCF) + { + usb_host_data->slider = 0xC9; + } + else if (report->slider <= 0xEF) + { + usb_host_data->slider = 0xE6; + } + else + { + usb_host_data->slider = 0x7F; + } + } + else + { + usb_host_data->slider = report->slider; + } + break; + } + case ROCK_BAND_DRUMS: + { + PS3RockBandDrums_Data_t *report = (PS3RockBandDrums_Data_t *)data; + uint8_t redVelocity = 255 - report->redVelocity; + uint8_t greenVelocity = 255 - report->greenVelocity; + uint8_t yellowVelocity = 255 - report->yellowVelocity; + uint8_t blueVelocity = 255 - report->blueVelocity; + bool kick1 = report->leftShoulder; + bool kick2 = report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + if (!report->padFlag && !report->cymbalFlag) + { + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + } + SET_RB_PADS(); + break; + } + case GUITAR_HERO_DRUMS: + { + PS3GuitarHeroDrums_Data_t *report = (PS3GuitarHeroDrums_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + SET_GH_PADS(); + // Forward any midi data we get + if ((report->midiByte0 & 0xF0) == 0x90) + { + onNote(report->midiByte0 & 0x0F, report->midiByte1, report->midiByte2); + } + else if ((report->midiByte0 & 0xF0) == 0x80) + { + offNote(report->midiByte0 & 0x0F, report->midiByte1, report->midiByte2); + } + break; + } + case LIVE_GUITAR: + { + PS3GHLGuitar_Data_t *report = (PS3GHLGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up || report->strumBar == 0x00; + usb_host_data->dpadDown |= down || report->strumBar == 0xFF; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + if (report->tilt != PS3_ACCEL_CENTER) + { + usb_host_data->tilt = (report->tilt - PS3_ACCEL_CENTER) << 6; + } + if (report->whammy) + { + usb_host_data->whammy = (report->whammy - PS3_STICK_CENTER) << 1; + } + break; + } + case DJ_HERO_TURNTABLE: + { + PS3Turntable_Data_t *report = (PS3Turntable_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->leftBlue |= report->leftBlue; + usb_host_data->leftRed |= report->leftRed; + usb_host_data->leftGreen |= report->leftGreen; + usb_host_data->rightBlue |= report->rightBlue; + usb_host_data->rightRed |= report->rightRed; + usb_host_data->rightGreen |= report->rightGreen; + if (report->effectsKnob != PS3_ACCEL_CENTER) + { + usb_host_data->effectsKnob = (report->effectsKnob - PS3_ACCEL_CENTER) << 6; + } + if (report->crossfader != PS3_ACCEL_CENTER) + { + usb_host_data->crossfader = (report->crossfader - PS3_ACCEL_CENTER) << 6; + } + if (report->leftTableVelocity != PS3_STICK_CENTER) + { + usb_host_data->leftTableVelocity = (report->leftTableVelocity - PS3_STICK_CENTER) << 8; + } + if (report->rightTableVelocity != PS3_STICK_CENTER) + { + usb_host_data->rightTableVelocity = (report->rightTableVelocity - PS3_STICK_CENTER) << 8; + } + break; + } + + case ROCK_BAND_PRO_GUITAR_SQUIRE: + case ROCK_BAND_PRO_GUITAR_MUSTANG: + { + PS3RockBandProGuitar_Data_t *report = (PS3RockBandProGuitar_Data_t *)data; + usb_host_data->dpadLeft |= left; + usb_host_data->dpadRight |= right; + usb_host_data->dpadUp |= up; + usb_host_data->dpadDown |= down; + TRANSLATE_PRO_GUITAR; + break; + } + } + break; + } + case LTEK_ID: + { + LTEK_Report_With_Id_Data_t *report = (LTEK_Report_With_Id_Data_t *)data; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + usb_host_data->start |= report->start; + usb_host_data->back |= report->back; + break; + } + case LTEK: + { + LTEK_Report_Data_t *report = (LTEK_Report_Data_t *)data; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + usb_host_data->start |= report->start; + usb_host_data->back |= report->back; + break; + } + case STEPMANIAX: + { + StepManiaX_Report_Data_t *report = (StepManiaX_Report_Data_t *)data; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + break; + } + case PS4: + { + PS4Dpad_Data_t *dpad = (PS4Dpad_Data_t *)data; + usb_host_data->dpadLeft |= dpad->dpad == 6 || dpad->dpad == 5 || dpad->dpad == 7; + usb_host_data->dpadRight |= dpad->dpad == 3 || dpad->dpad == 2 || dpad->dpad == 1; + usb_host_data->dpadUp |= dpad->dpad == 0 || dpad->dpad == 1 || dpad->dpad == 7; + usb_host_data->dpadDown |= dpad->dpad == 5 || dpad->dpad == 4 || dpad->dpad == 3; + switch (device_type.sub_type) + { + case GAMEPAD: + { + PS4Gamepad_Data_t *report = (PS4Gamepad_Data_t *)data; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + usb_host_data->capture |= report->capture; + if (report->leftTrigger) + { + usb_host_data->leftTrigger = report->leftTrigger << 8; + } + if (report->rightTrigger) + { + usb_host_data->rightTrigger = report->rightTrigger << 8; + } + if (report->leftStickX != PS3_STICK_CENTER) + { + usb_host_data->leftStickX = (report->leftStickX - PS3_STICK_CENTER) << 8; + } + if (report->leftStickY != PS3_STICK_CENTER) + { + usb_host_data->leftStickY = (((UINT8_MAX - report->leftStickY) - PS3_STICK_CENTER)) << 8; + } + if (report->rightStickX != PS3_STICK_CENTER) + { + usb_host_data->rightStickX = (report->rightStickX - PS3_STICK_CENTER) << 8; + } + if (report->rightStickY != PS3_STICK_CENTER) + { + usb_host_data->rightStickY = (((UINT8_MAX - report->rightStickY) - PS3_STICK_CENTER)) << 8; + } + break; + } + case ROCK_BAND_GUITAR: + { + PS4RockBandGuitar_Data_t *report = (PS4RockBandGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + if (report->tilt) + { + usb_host_data->tilt = report->tilt << 7; + } + if (report->solo) + { + usb_host_data->soloGreen |= report->a; + usb_host_data->soloRed |= report->b; + usb_host_data->soloYellow |= report->y; + usb_host_data->soloBlue |= report->x; + usb_host_data->soloOrange |= report->leftShoulder; + } + if (report->whammy) + { + usb_host_data->whammy = report->whammy; + } + if (report->pickup) + { + usb_host_data->pickup = report->pickup; + } + break; + } + case LIVE_GUITAR: + { + PS4GHLGuitar_Data_t *report = (PS4GHLGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadUp |= report->strumBar == 0x00; + usb_host_data->dpadDown |= report->strumBar == 0xFF; + if (report->tilt != PS3_ACCEL_CENTER) + { + usb_host_data->tilt = (report->tilt - PS3_ACCEL_CENTER) << 6; + } + if (report->whammy) + { + usb_host_data->whammy = report->whammy; + } + break; + } + } + break; + } + case PS5: + { + PS5Dpad_Data_t *dpad = (PS5Dpad_Data_t *)data; + usb_host_data->dpadLeft |= dpad->dpad == 6 || dpad->dpad == 5 || dpad->dpad == 7; + usb_host_data->dpadRight |= dpad->dpad == 3 || dpad->dpad == 2 || dpad->dpad == 1; + usb_host_data->dpadUp |= dpad->dpad == 0 || dpad->dpad == 1 || dpad->dpad == 7; + usb_host_data->dpadDown |= dpad->dpad == 5 || dpad->dpad == 4 || dpad->dpad == 3; + switch (device_type.sub_type) + { + case GAMEPAD: + { + PS5Gamepad_Data_t *report = (PS5Gamepad_Data_t *)data; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + if (report->leftTrigger) + { + usb_host_data->leftTrigger = report->leftTrigger << 8; + } + if (report->rightTrigger) + { + usb_host_data->rightTrigger = report->rightTrigger << 8; + } + if (report->leftStickX != PS3_STICK_CENTER) + { + usb_host_data->leftStickX = (report->leftStickX - PS3_STICK_CENTER) << 8; + } + if (report->leftStickY != PS3_STICK_CENTER) + { + usb_host_data->leftStickY = (((UINT8_MAX - report->leftStickY) - PS3_STICK_CENTER)) << 8; + } + if (report->rightStickX != PS3_STICK_CENTER) + { + usb_host_data->rightStickX = (report->rightStickX - PS3_STICK_CENTER) << 8; + } + if (report->rightStickY != PS3_STICK_CENTER) + { + usb_host_data->rightStickY = (((UINT8_MAX - report->rightStickY) - PS3_STICK_CENTER)) << 8; + } + break; + } + case ROCK_BAND_GUITAR: + { + PS5RockBandGuitar_Data_t *report = (PS5RockBandGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + if (report->tilt) + { + usb_host_data->tilt = report->tilt << 7; + } + if (report->solo) + { + usb_host_data->soloGreen |= report->a; + usb_host_data->soloRed |= report->b; + usb_host_data->soloYellow |= report->y; + usb_host_data->soloBlue |= report->x; + usb_host_data->soloOrange |= report->leftShoulder; + } + if (report->whammy) + { + usb_host_data->whammy = report->whammy; + } + break; + } + } + break; + } + case SWITCH: + { + switch (device_type.sub_type) + { + case GAMEPAD: + { + SwitchProGamepad_Data_t *report = (SwitchProGamepad_Data_t *)data; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->capture |= report->capture; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + if (report->leftTrigger) + { + usb_host_data->leftTrigger = report->leftTrigger << 8; + } + if (report->rightTrigger) + { + usb_host_data->rightTrigger = report->rightTrigger << 8; + } + if (report->leftStickX != 0x800) + { + usb_host_data->leftStickX = (report->leftStickX - 0x800) << 4; + } + if (report->leftStickY != 0x800) + { + usb_host_data->leftStickY = (((0xFFF - report->leftStickY) - 0x800)) << 4; + } + if (report->rightStickX != 0x800) + { + usb_host_data->rightStickX = (report->rightStickX - 0x800) << 4; + } + if (report->rightStickY != 0x800) + { + usb_host_data->rightStickY = (((0xFFF - report->rightStickY) - 0x800)) << 4; + } + break; + } + case TAIKO: + { + SwitchTaiko_Data_t *report = (SwitchTaiko_Data_t *)data; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + usb_host_data->dpadLeft |= report->dpad == 6 || report->dpad == 5 || report->dpad == 7; + usb_host_data->dpadRight |= report->dpad == 3 || report->dpad == 2 || report->dpad == 1; + usb_host_data->dpadUp |= report->dpad == 0 || report->dpad == 1 || report->dpad == 7; + usb_host_data->dpadDown |= report->dpad == 5 || report->dpad == 4 || report->dpad == 3; + if (report->l2) + { + usb_host_data->leftTrigger = UINT16_MAX; + } + if (report->r2) + { + usb_host_data->rightTrigger = UINT16_MAX; + } + break; + } + } + break; + } + case SWITCH2: + { + switch (device_type.sub_type) + { + case GAMEPAD: + { + if (data[0] == SWITCH_2_GC_FULL_REPORT_ID) + { + Switch2ProGamepadGC_Data_t *report = (Switch2ProGamepadGC_Data_t *)data; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->capture |= report->capture; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + if (report->leftTrigger) + { + usb_host_data->leftTrigger = report->leftTrigger << 8; + } + if (report->rightTrigger) + { + usb_host_data->rightTrigger = report->rightTrigger << 8; + } + if (report->leftStickX != SWITCH_2_STICK_CENTER) + { + usb_host_data->leftStickX = (report->leftStickX - SWITCH_2_STICK_CENTER) << 4; + } + if (report->leftStickY != SWITCH_2_STICK_CENTER) + { + usb_host_data->leftStickY = ((report->leftStickY - SWITCH_2_STICK_CENTER)) << 4; + } + if (report->rightStickX != SWITCH_2_STICK_CENTER) + { + usb_host_data->rightStickX = (report->rightStickX - SWITCH_2_STICK_CENTER) << 4; + } + if (report->rightStickY != SWITCH_2_STICK_CENTER) + { + usb_host_data->rightStickY = ((report->rightStickY - SWITCH_2_STICK_CENTER)) << 4; + } + } + else + { + Switch2ProGamepad_Data_t *report = (Switch2ProGamepad_Data_t *)data; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->capture |= report->capture; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + if (report->l2) + { + usb_host_data->leftTrigger = 0xFFFF; + } + if (report->r2) + { + usb_host_data->rightTrigger = 0xFFFF; + } + if (report->leftStickX != SWITCH_2_STICK_CENTER) + { + usb_host_data->leftStickX = (report->leftStickX - SWITCH_2_STICK_CENTER) << 4; + } + if (report->leftStickY != SWITCH_2_STICK_CENTER) + { + usb_host_data->leftStickY = ((report->leftStickY - SWITCH_2_STICK_CENTER)) << 4; + } + if (report->rightStickX != SWITCH_2_STICK_CENTER) + { + usb_host_data->rightStickX = (report->rightStickX - SWITCH_2_STICK_CENTER) << 4; + } + if (report->rightStickY != SWITCH_2_STICK_CENTER) + { + usb_host_data->rightStickY = ((report->rightStickY - SWITCH_2_STICK_CENTER)) << 4; + } + } + break; + } + } + break; + } + case OG_XBOX: + { + OGXboxGamepad_Data_t *report = (OGXboxGamepad_Data_t *)data; + usb_host_data->a |= report->a > 0x20; + usb_host_data->b |= report->b > 0x20; + usb_host_data->x |= report->x > 0x20; + usb_host_data->y |= report->y > 0x20; + usb_host_data->leftShoulder |= report->leftShoulder > 0x20; + usb_host_data->rightShoulder |= report->rightShoulder > 0x20; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + if (report->leftTrigger) + { + usb_host_data->leftTrigger = report->leftTrigger << 8; + } + if (report->rightTrigger) + { + usb_host_data->rightTrigger = report->rightTrigger << 8; + } + if (report->leftStickX) + { + usb_host_data->leftStickX = report->leftStickX; + } + if (report->leftStickY) + { + usb_host_data->leftStickY = report->leftStickY; + } + if (report->rightStickX) + { + usb_host_data->rightStickX = report->rightStickX; + } + if (report->rightStickY) + { + usb_host_data->rightStickY = report->rightStickY; + } + if (report->leftShoulder) + { + usb_host_data->pressureL1 = report->leftShoulder; + } + if (report->rightShoulder) + { + usb_host_data->pressureR1 = report->rightShoulder; + } + if (report->y) + { + usb_host_data->pressureTriangle = report->y; + } + if (report->b) + { + usb_host_data->pressureCircle = report->b; + } + if (report->a) + { + usb_host_data->pressureCross = report->a; + } + if (report->x) + { + usb_host_data->pressureSquare = report->x; + } + break; + } + case XBOX360_BB: + { + XInputBigButton_Data_t *report = (XInputBigButton_Data_t *)data; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + break; + } + + case XINPUTCOMPAT_NEO_S: + { + XInputCompatGamepad2_Data_t *report = (XInputCompatGamepad2_Data_t *)data; + if (report->rid == 2) + { + usb_host_data->guide = data[1]; + break; + } + if (report->rid == 1) + { + uint8_t dpad = report->dpad - 1; + usb_host_data->dpadLeft |= dpad == 6 || dpad == 5 || dpad == 7; + usb_host_data->dpadRight |= dpad == 3 || dpad == 2 || dpad == 1; + usb_host_data->dpadUp |= dpad == 0 || dpad == 1 || dpad == 7; + usb_host_data->dpadDown |= dpad == 5 || dpad == 4 || dpad == 3; + +#if DEVICE_TYPE_IS_GUITAR + // Festival pro mode mappings + usb_host_data->green |= dpad == 6 || dpad == 5 || dpad == 7; + usb_host_data->red |= dpad == 0 || dpad == 1 || dpad == 7; + usb_host_data->yellow |= report->x; + usb_host_data->blue |= report->y; + usb_host_data->orange |= report->b; +#endif + // Festival expert mappings + // usb_host_data->green |= dpad == 6 || dpad == 5 || dpad == 7; + // usb_host_data->red |= dpad == 3 || dpad == 2 || dpad == 1; + // usb_host_data->yellow |= report->x; + // usb_host_data->blue |= report->y; + // usb_host_data->orange |= report->b; + + // Festival easy/med/hard mappings + // usb_host_data->green |= dpad == 6 || dpad == 5 || dpad == 7; + // usb_host_data->red |= dpad == 3 || dpad == 2 || dpad == 1; + // usb_host_data->yellow |= report->x; + // usb_host_data->blue |= report->b; + // usb_host_data->orange |= report->y; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + if (report->leftTrigger) + { + usb_host_data->leftTrigger = report->leftTrigger << 6; + } + if (report->rightTrigger) + { + usb_host_data->rightTrigger = report->rightTrigger << 6; + } + if (report->leftStickX) + { + usb_host_data->leftStickX = report->leftStickX - INT16_MAX; + } + if (report->leftStickY) + { + usb_host_data->leftStickY = -(report->leftStickY - INT16_MAX); + } + if (report->rightStickX) + { + usb_host_data->rightStickX = report->rightStickX - INT16_MAX; + } + if (report->rightStickY) + { + usb_host_data->rightStickY = -(report->rightStickY - INT16_MAX); + } + } + break; + } + case XINPUTCOMPAT: + { + XInputCompatGamepad_Data_t *report = (XInputCompatGamepad_Data_t *)data; + if (report->rid == 1) + { + uint8_t dpad = report->dpad - 1; + usb_host_data->dpadLeft |= dpad == 6 || dpad == 5 || dpad == 7; + usb_host_data->dpadRight |= dpad == 3 || dpad == 2 || dpad == 1; + usb_host_data->dpadUp |= dpad == 0 || dpad == 1 || dpad == 7; + usb_host_data->dpadDown |= dpad == 5 || dpad == 4 || dpad == 3; + + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->capture |= report->capture; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + if (report->leftTrigger) + { + usb_host_data->leftTrigger = report->leftTrigger << 6; + } + if (report->rightTrigger) + { + usb_host_data->rightTrigger = report->rightTrigger << 6; + } + if (report->leftStickX != 0x8000) + { + usb_host_data->leftStickX = report->leftStickX - 0x8000; + } + if (report->leftStickY != 0x8000) + { + usb_host_data->leftStickY = ((UINT16_MAX - report->leftStickY) - 0x8000); + } + if (report->rightStickX != 0x8000) + { + usb_host_data->rightStickX = report->rightStickX - 0x8000; + } + if (report->rightStickY != 0x8000) + { + usb_host_data->rightStickY = ((UINT16_MAX - report->rightStickY) - 0x8000); + } + } + break; + } + case XBOX360_W: + case XBOX360: + { + switch (device_type.sub_type) + { + case XINPUT_GUITAR_BASS: + case XINPUT_GUITAR: + { + XInputRockBandGuitar_Data_t *report = (XInputRockBandGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + if (report->tilt) + { + usb_host_data->tilt = INT16_MAX; + } + if (report->solo) + { + usb_host_data->soloGreen |= report->a; + usb_host_data->soloRed |= report->b; + usb_host_data->soloYellow |= report->y; + usb_host_data->soloBlue |= report->x; + usb_host_data->soloOrange |= report->leftShoulder; + } + if (report->whammy) + { + usb_host_data->whammy = (report->whammy >> 8) - PS3_STICK_CENTER; + } + if (report->pickup) + { + usb_host_data->pickup = report->pickup; + } + break; + } + case XINPUT_GUITAR_WT: + case XINPUT_GUITAR_ALTERNATE: + { + XInputGuitarHeroGuitar_Data_t *report = (XInputGuitarHeroGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + if (report->tilt) + { + usb_host_data->tilt = report->tilt; + } + if (report->whammy) + { + usb_host_data->whammy = (report->whammy >> 8) - PS3_STICK_CENTER; + } + + uint8_t slider = (report->slider >> 8) ^ 0x80; + + if (device_type.sub_type == XINPUT_GUITAR_WT) + { + if (slider < 0x2F) + { + usb_host_data->slider = 0x15; } - case LIVE_GUITAR: { - PCGHLGuitar_Data_t *report = (PCGHLGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - if (report->tilt != PS3_STICK_CENTER) { - usb_host_data->tilt = (report->tilt - PS3_STICK_CENTER) << 8; - } - if (report->whammy) { - usb_host_data->whammy = report->whammy; - } - break; + else if (slider <= 0x3F) + { + usb_host_data->slider = 0x30; } - case DJ_HERO_TURNTABLE: { - PCTurntable_Data_t *report = (PCTurntable_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftBlue |= report->leftBlue; - usb_host_data->leftRed |= report->leftRed; - usb_host_data->leftGreen |= report->leftGreen; - usb_host_data->rightBlue |= report->rightBlue; - usb_host_data->rightRed |= report->rightRed; - usb_host_data->rightGreen |= report->rightGreen; - if (report->effectsKnob != PS3_ACCEL_CENTER) { - usb_host_data->effectsKnob = (report->effectsKnob - PS3_ACCEL_CENTER) << 6; - } - if (report->crossfader != PS3_ACCEL_CENTER) { - usb_host_data->crossfader = (report->crossfader - PS3_ACCEL_CENTER) << 6; - } - if (report->leftTableVelocity != PS3_STICK_CENTER) { - usb_host_data->leftTableVelocity = (report->leftTableVelocity - PS3_STICK_CENTER) << 8; - } - if (report->rightTableVelocity != PS3_STICK_CENTER) { - usb_host_data->rightTableVelocity = (report->rightTableVelocity - PS3_STICK_CENTER) << 8; - } - break; + else if (slider <= 0x5F) + { + usb_host_data->slider = 0x4D; } - case ROCK_BAND_PRO_KEYS: { - PCRockBandProKeyboard_Data_t *report = (PCRockBandProKeyboard_Data_t *)data; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - TRANSLATE_PRO_KEYS; - break; + else if (slider <= 0x6F) + { + usb_host_data->slider = 0x66; } - case ROCK_BAND_PRO_GUITAR_SQUIRE: - case ROCK_BAND_PRO_GUITAR_MUSTANG: { - PCRockBandProGuitar_Data_t *report = (PCRockBandProGuitar_Data_t *)data; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - TRANSLATE_PRO_GUITAR; - break; + else if (slider <= 0x8F) + { + usb_host_data->slider = 0x80; } - } - break; - } - case PS3: { - PS3Dpad_Data_t *report = (PS3Dpad_Data_t *)data; - uint8_t dpad = report->dpad >= 0x08 ? 0 : dpad_bindings_reverse[report->dpad]; - asm volatile("" :: - : "memory"); - bool up = dpad & UP; - bool left = dpad & LEFT; - bool down = dpad & DOWN; - bool right = dpad & RIGHT; - switch (device_type.sub_type) { - case GAMEPAD: { - PS3Gamepad_Data_t *report = (PS3Gamepad_Data_t *)data; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->rightThumbClick |= report->rightThumbClick; - usb_host_data->dpadLeft |= report->dpadLeft; - usb_host_data->dpadRight |= report->dpadRight; - usb_host_data->dpadUp |= report->dpadUp; - usb_host_data->dpadDown |= report->dpadDown; - if (report->leftTrigger) { - usb_host_data->leftTrigger = report->leftTrigger << 8; - } - if (report->rightTrigger) { - usb_host_data->rightTrigger = report->rightTrigger << 8; - } - if (report->leftStickX != PS3_STICK_CENTER) { - usb_host_data->leftStickX = (report->leftStickX - PS3_STICK_CENTER) << 8; - } - if (report->leftStickY != PS3_STICK_CENTER) { - usb_host_data->leftStickY = (((UINT8_MAX - report->leftStickY) - PS3_STICK_CENTER)) << 8; - } - if (report->rightStickX != PS3_STICK_CENTER) { - usb_host_data->rightStickX = (report->rightStickX - PS3_STICK_CENTER) << 8; - } - if (report->rightStickY != PS3_STICK_CENTER) { - usb_host_data->rightStickY = (((UINT8_MAX - report->rightStickY) - PS3_STICK_CENTER)) << 8; - } - if (report->pressureDpadUp) { - usb_host_data->pressureDpadUp = report->pressureDpadUp; - } - if (report->pressureDpadRight) { - usb_host_data->pressureDpadRight = report->pressureDpadRight; - } - if (report->pressureDpadDown) { - usb_host_data->pressureDpadDown = report->pressureDpadDown; - } - if (report->pressureDpadLeft) { - usb_host_data->pressureDpadLeft = report->pressureDpadLeft; - } - if (report->pressureL1) { - usb_host_data->pressureL1 = report->pressureL1; - } - if (report->pressureR1) { - usb_host_data->pressureR1 = report->pressureR1; - } - if (report->pressureTriangle) { - usb_host_data->pressureTriangle = report->pressureTriangle; - } - if (report->pressureCircle) { - usb_host_data->pressureCircle = report->pressureCircle; - } - if (report->pressureCross) { - usb_host_data->pressureCross = report->pressureCross; - } - if (report->pressureSquare) { - usb_host_data->pressureSquare = report->pressureSquare; - } - break; + else if (slider <= 0x9F) + { + usb_host_data->slider = 0x9A; } - - case ROCK_BAND_PRO_KEYS: { - PS3RockBandProKeyboard_Data_t *report = (PS3RockBandProKeyboard_Data_t *)data; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - TRANSLATE_PRO_KEYS; - break; + else if (slider <= 0xAF) + { + usb_host_data->slider = 0xAF; } - case ROCK_BAND_GUITAR: { - PS3RockBandGuitar_Data_t *report = (PS3RockBandGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - if (report->tilt) { - usb_host_data->tilt = INT16_MAX; - } - if (report->solo) { - usb_host_data->soloGreen |= report->a; - usb_host_data->soloRed |= report->b; - usb_host_data->soloYellow |= report->y; - usb_host_data->soloBlue |= report->x; - usb_host_data->soloOrange |= report->leftShoulder; - } - if (report->whammy) { - usb_host_data->whammy = report->whammy; - } - if (report->pickup) { - usb_host_data->pickup = report->pickup; - } - break; + else if (slider <= 0xCF) + { + usb_host_data->slider = 0xC9; } - case GUITAR_HERO_GUITAR_WT: - case GUITAR_HERO_GUITAR: { - PS3GuitarHeroGuitar_Data_t *report = (PS3GuitarHeroGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - if (report->tilt != PS3_ACCEL_CENTER) { - usb_host_data->tilt = (report->tilt - PS3_ACCEL_CENTER) << 6; - } - if (report->whammy) { - usb_host_data->whammy = report->whammy; - } - // Detect GH5 vs WT. Wait for a neutral input, then use that to detect instrument type - if (device_type.sub_type == GUITAR_HERO_GUITAR_WT) { - // Its WT, convert to GH5 - if (report->slider <= 0x2F) { - usb_host_data->slider = 0x15; - } else if (report->slider <= 0x3F) { - usb_host_data->slider = 0x30; - } else if (report->slider <= 0x5F) { - usb_host_data->slider = 0x4D; - } else if (report->slider <= 0x6F) { - usb_host_data->slider = 0x66; - } else if (report->slider <= 0x8F) { - usb_host_data->slider = 0x80; - } else if (report->slider <= 0x9F) { - usb_host_data->slider = 0x9A; - } else if (report->slider <= 0xAF) { - usb_host_data->slider = 0xAF; - } else if (report->slider <= 0xCF) { - usb_host_data->slider = 0xC9; - } else if (report->slider <= 0xEF) { - usb_host_data->slider = 0xE6; - } else { - usb_host_data->slider = 0x7F; - } - } else { - usb_host_data->slider = report->slider; - } - break; + else if (slider <= 0xEF) + { + usb_host_data->slider = 0xE6; } - case ROCK_BAND_DRUMS: { - PS3RockBandDrums_Data_t *report = (PS3RockBandDrums_Data_t *)data; - uint8_t redVelocity = ~report->redVelocity; - uint8_t greenVelocity = ~report->greenVelocity; - uint8_t yellowVelocity = ~report->yellowVelocity; - uint8_t blueVelocity = ~report->blueVelocity; - bool kick1 = report->leftShoulder; - bool kick2 = report->rightShoulder; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - SET_RB_PADS(); - break; + else + { + usb_host_data->slider = 0xFF; } - case GUITAR_HERO_DRUMS: { - PS3GuitarHeroDrums_Data_t *report = (PS3GuitarHeroDrums_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - SET_GH_PADS(); - // Forward any midi data we get - if ((report->midiByte0 & 0xF0) == 0x90) { - onNote(report->midiByte0 & 0x0F, report->midiByte1, report->midiByte2); - } else if ((report->midiByte0 & 0xF0) == 0x80) { - offNote(report->midiByte0 & 0x0F, report->midiByte1, report->midiByte2); - } - break; + } + else + { + usb_host_data->slider = slider; + } + break; + } + case XINPUT_DRUMS: + { + if (device_type.drum_type == DRUM_GH) + { + XInputGuitarHeroDrums_Data_t *report = (XInputGuitarHeroDrums_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + SET_GH_PADS(); + // Forward any midi data we get + if ((report->midiPacket[0] & 0xF0) == 0x90) + { + onNote(report->midiPacket[0] & 0x0F, report->midiPacket[1], report->midiPacket[2]); } - case LIVE_GUITAR: { - PS3GHLGuitar_Data_t *report = (PS3GHLGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up || report->strumBar == 0x00; - usb_host_data->dpadDown |= down || report->strumBar == 0xFF; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - if (report->tilt != PS3_ACCEL_CENTER) { - usb_host_data->tilt = (report->tilt - PS3_ACCEL_CENTER) << 6; - } - if (report->whammy) { - usb_host_data->whammy = report->whammy << 8; - } - break; + else if ((report->midiPacket[0] & 0xF0) == 0x80) + { + offNote(report->midiPacket[0] & 0x0F, report->midiPacket[1], report->midiPacket[2]); } - case DJ_HERO_TURNTABLE: { - PS3Turntable_Data_t *report = (PS3Turntable_Data_t *)data; + } + else + { + XInputRockBandDrums_Data_t *report = (XInputRockBandDrums_Data_t *)data; + bool up = report->dpadUp; + bool down = report->dpadDown; + bool left = report->dpadLeft; + bool right = report->dpadRight; + bool kick1 = report->leftShoulder; + bool kick2 = report->leftThumbClick; + + uint8_t redVelocity = xinput_rb_velocity_positive(report->redVelocity); + uint8_t greenVelocity = xinput_rb_velocity_negative(report->greenVelocity); + uint8_t yellowVelocity = xinput_rb_velocity_negative(report->yellowVelocity); + uint8_t blueVelocity = xinput_rb_velocity_positive(report->blueVelocity); + + SET_RB_PADS(); + + if (!report->padFlag && !report->cymbalFlag) + { usb_host_data->a |= report->a; usb_host_data->b |= report->b; usb_host_data->x |= report->x; usb_host_data->y |= report->y; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftBlue |= report->leftBlue; - usb_host_data->leftRed |= report->leftRed; - usb_host_data->leftGreen |= report->leftGreen; - usb_host_data->rightBlue |= report->rightBlue; - usb_host_data->rightRed |= report->rightRed; - usb_host_data->rightGreen |= report->rightGreen; - if (report->effectsKnob != PS3_ACCEL_CENTER) { - usb_host_data->effectsKnob = (report->effectsKnob - PS3_ACCEL_CENTER) << 6; - } - if (report->crossfader != PS3_ACCEL_CENTER) { - usb_host_data->crossfader = (report->crossfader - PS3_ACCEL_CENTER) << 6; - } - if (report->leftTableVelocity != PS3_STICK_CENTER) { - usb_host_data->leftTableVelocity = (report->leftTableVelocity - PS3_STICK_CENTER) << 8; - } - if (report->rightTableVelocity != PS3_STICK_CENTER) { - usb_host_data->rightTableVelocity = (report->rightTableVelocity - PS3_STICK_CENTER) << 8; - } - break; - } - - case ROCK_BAND_PRO_GUITAR_SQUIRE: - case ROCK_BAND_PRO_GUITAR_MUSTANG: { - PS3RockBandProGuitar_Data_t *report = (PS3RockBandProGuitar_Data_t *)data; - usb_host_data->dpadLeft |= left; - usb_host_data->dpadRight |= right; - usb_host_data->dpadUp |= up; - usb_host_data->dpadDown |= down; - TRANSLATE_PRO_GUITAR; - break; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; } + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; } break; } - case LTEK_ID: { - LTEK_Report_With_Id_Data_t *report = (LTEK_Report_With_Id_Data_t *)data; + case XINPUT_GUITAR_HERO_LIVE: + { + XInputGHLGuitar_Data_t *report = (XInputGHLGuitar_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; usb_host_data->dpadLeft |= report->dpadLeft; usb_host_data->dpadRight |= report->dpadRight; usb_host_data->dpadUp |= report->dpadUp; usb_host_data->dpadDown |= report->dpadDown; - usb_host_data->start |= report->start; + usb_host_data->leftThumbClick |= report->leftThumbClick; usb_host_data->back |= report->back; - break; - } - case LTEK: { - LTEK_Report_Data_t *report = (LTEK_Report_Data_t *)data; - usb_host_data->dpadLeft |= report->dpadLeft; - usb_host_data->dpadRight |= report->dpadRight; - usb_host_data->dpadUp |= report->dpadUp; - usb_host_data->dpadDown |= report->dpadDown; usb_host_data->start |= report->start; - usb_host_data->back |= report->back; + usb_host_data->guide |= report->guide; + if (report->tilt) + { + usb_host_data->tilt = report->tilt; + } + if (report->whammy) + { + usb_host_data->whammy = report->whammy; + } break; } - case STEPMANIAX: { - StepManiaX_Report_Data_t *report = (StepManiaX_Report_Data_t *)data; + case XINPUT_TURNTABLE: + { + XInputTurntable_Data_t *report = (XInputTurntable_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; usb_host_data->dpadLeft |= report->dpadLeft; usb_host_data->dpadRight |= report->dpadRight; usb_host_data->dpadUp |= report->dpadUp; usb_host_data->dpadDown |= report->dpadDown; - break; - } - case PS4: { - PS4Dpad_Data_t *dpad = (PS4Dpad_Data_t *)data; - usb_host_data->dpadLeft = dpad->dpad == 6 || dpad->dpad == 5 || dpad->dpad == 7; - usb_host_data->dpadRight = dpad->dpad == 3 || dpad->dpad == 2 || dpad->dpad == 1; - usb_host_data->dpadUp = dpad->dpad == 0 || dpad->dpad == 1 || dpad->dpad == 7; - usb_host_data->dpadDown = dpad->dpad == 5 || dpad->dpad == 4 || dpad->dpad == 3; - switch (device_type.sub_type) { - case GAMEPAD: { - PS4Gamepad_Data_t *report = (PS4Gamepad_Data_t *)data; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->rightThumbClick |= report->rightThumbClick; - usb_host_data->capture |= report->capture; - if (report->leftTrigger) { - usb_host_data->leftTrigger = report->leftTrigger << 8; - } - if (report->rightTrigger) { - usb_host_data->rightTrigger = report->rightTrigger << 8; - } - if (report->leftStickX != PS3_STICK_CENTER) { - usb_host_data->leftStickX = (report->leftStickX - PS3_STICK_CENTER) << 8; - } - if (report->leftStickY != PS3_STICK_CENTER) { - usb_host_data->leftStickY = (((UINT8_MAX - report->leftStickY) - PS3_STICK_CENTER)) << 8; - } - if (report->rightStickX != PS3_STICK_CENTER) { - usb_host_data->rightStickX = (report->rightStickX - PS3_STICK_CENTER) << 8; - } - if (report->rightStickY != PS3_STICK_CENTER) { - usb_host_data->rightStickY = (((UINT8_MAX - report->rightStickY) - PS3_STICK_CENTER)) << 8; - } - break; - } - case ROCK_BAND_GUITAR: { - PS4RockBandGuitar_Data_t *report = (PS4RockBandGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - if (report->tilt) { - usb_host_data->tilt = report->tilt << 7; - } - if (report->solo) { - usb_host_data->soloGreen |= report->a; - usb_host_data->soloRed |= report->b; - usb_host_data->soloYellow |= report->y; - usb_host_data->soloBlue |= report->x; - usb_host_data->soloOrange |= report->leftShoulder; - } - if (report->whammy) { - usb_host_data->whammy = report->whammy; - } - if (report->pickup) { - usb_host_data->pickup = report->pickup; - } - break; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; + usb_host_data->leftBlue |= report->leftBlue; + usb_host_data->leftRed |= report->leftRed; + usb_host_data->leftGreen |= report->leftGreen; + usb_host_data->rightBlue |= report->rightBlue; + usb_host_data->rightRed |= report->rightRed; + usb_host_data->rightGreen |= report->rightGreen; + if (report->effectsKnob) + { + usb_host_data->effectsKnob = report->effectsKnob; + } + if (report->crossfader) + { + usb_host_data->crossfader = report->crossfader; + } + if (report->leftTableVelocity) + { + if (report->leftTableVelocity > 127) + { + report->leftTableVelocity = 127; } - case LIVE_GUITAR: { - PS4GHLGuitar_Data_t *report = (PS4GHLGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadUp |= report->strumBar == 0x00; - usb_host_data->dpadDown |= report->strumBar == 0xFF; - if (report->tilt != PS3_ACCEL_CENTER) { - usb_host_data->tilt = (report->tilt - PS3_ACCEL_CENTER) << 6; - } - if (report->whammy) { - usb_host_data->whammy = report->whammy; - } - break; + if (report->leftTableVelocity < -127) + { + report->leftTableVelocity = -127; } + usb_host_data->leftTableVelocity = report->leftTableVelocity << 8; } - break; - } - case PS5: { - PS5Gamepad_Data_t *dpad = (PS5Gamepad_Data_t *)data; - usb_host_data->dpadLeft = dpad->dpad == 6 || dpad->dpad == 5 || dpad->dpad == 7; - usb_host_data->dpadRight = dpad->dpad == 3 || dpad->dpad == 2 || dpad->dpad == 1; - usb_host_data->dpadUp = dpad->dpad == 0 || dpad->dpad == 1 || dpad->dpad == 7; - usb_host_data->dpadDown = dpad->dpad == 5 || dpad->dpad == 4 || dpad->dpad == 3; - switch (device_type.sub_type) { - case GAMEPAD: { - PS5Gamepad_Data_t *report = (PS5Gamepad_Data_t *)data; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->rightThumbClick |= report->rightThumbClick; - if (report->leftTrigger) { - usb_host_data->leftTrigger = report->leftTrigger << 8; - } - if (report->rightTrigger) { - usb_host_data->rightTrigger = report->rightTrigger << 8; - } - if (report->leftStickX != PS3_STICK_CENTER) { - usb_host_data->leftStickX = (report->leftStickX - PS3_STICK_CENTER) << 8; - } - if (report->leftStickY != PS3_STICK_CENTER) { - usb_host_data->leftStickY = (((UINT8_MAX - report->leftStickY) - PS3_STICK_CENTER)) << 8; - } - if (report->rightStickX != PS3_STICK_CENTER) { - usb_host_data->rightStickX = (report->rightStickX - PS3_STICK_CENTER) << 8; - } - if (report->rightStickY != PS3_STICK_CENTER) { - usb_host_data->rightStickY = (((UINT8_MAX - report->rightStickY) - PS3_STICK_CENTER)) << 8; - } - break; + if (report->rightTableVelocity) + { + if (report->rightTableVelocity > 127) + { + report->rightTableVelocity = 127; } - case ROCK_BAND_GUITAR: { - PS5RockBandGuitar_Data_t *report = (PS5RockBandGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - if (report->tilt) { - usb_host_data->tilt = report->tilt << 7; - } - if (report->solo) { - usb_host_data->soloGreen |= report->a; - usb_host_data->soloRed |= report->b; - usb_host_data->soloYellow |= report->y; - usb_host_data->soloBlue |= report->x; - usb_host_data->soloOrange |= report->leftShoulder; - } - if (report->whammy) { - usb_host_data->whammy = report->whammy; - } - break; + if (report->rightTableVelocity < -127) + { + report->rightTableVelocity = -127; } + usb_host_data->rightTableVelocity = report->rightTableVelocity << 8; } break; } - case SWITCH: { - switch (device_type.sub_type) { - case GAMEPAD: { - SwitchProGamepad_Data_t *report = (SwitchProGamepad_Data_t *)data; - usb_host_data->dpadLeft = report->dpad == 6 || report->dpad == 5 || report->dpad == 7; - usb_host_data->dpadRight = report->dpad == 3 || report->dpad == 2 || report->dpad == 1; - usb_host_data->dpadUp = report->dpad == 0 || report->dpad == 1 || report->dpad == 7; - usb_host_data->dpadDown = report->dpad == 5 || report->dpad == 4 || report->dpad == 3; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->capture |= report->capture; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->rightThumbClick |= report->rightThumbClick; - if (report->leftTrigger) { - usb_host_data->leftTrigger = report->leftTrigger << 8; - } - if (report->rightTrigger) { - usb_host_data->rightTrigger = report->rightTrigger << 8; - } - if (report->leftStickX != PS3_STICK_CENTER) { - usb_host_data->leftStickX = (report->leftStickX - PS3_STICK_CENTER) << 8; - } - if (report->leftStickY != PS3_STICK_CENTER) { - usb_host_data->leftStickY = (((UINT8_MAX - report->leftStickY) - PS3_STICK_CENTER)) << 8; - } - if (report->rightStickX != PS3_STICK_CENTER) { - usb_host_data->rightStickX = (report->rightStickX - PS3_STICK_CENTER) << 8; - } - if (report->rightStickY != PS3_STICK_CENTER) { - usb_host_data->rightStickY = (((UINT8_MAX - report->rightStickY) - PS3_STICK_CENTER)) << 8; - } - break; - } - case TAIKO: { - SwitchTaiko_Data_t *report = (SwitchTaiko_Data_t *)data; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->rightThumbClick |= report->rightThumbClick; - usb_host_data->dpadLeft = report->dpad == 6 || report->dpad == 5 || report->dpad == 7; - usb_host_data->dpadRight = report->dpad == 3 || report->dpad == 2 || report->dpad == 1; - usb_host_data->dpadUp = report->dpad == 0 || report->dpad == 1 || report->dpad == 7; - usb_host_data->dpadDown = report->dpad == 5 || report->dpad == 4 || report->dpad == 3; - if (report->l2) { - usb_host_data->leftTrigger = UINT16_MAX; - } - if (report->r2) { - usb_host_data->rightTrigger = UINT16_MAX; - } - break; - } - } + case XINPUT_PRO_KEYS: + { + XInputRockBandKeyboard_Data_t *report = (XInputRockBandKeyboard_Data_t *)data; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + + TRANSLATE_PRO_KEYS; + break; + } + case XINPUT_PRO_GUITAR: + { + XInputRockBandProGuitar_Data_t *report = (XInputRockBandProGuitar_Data_t *)data; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + TRANSLATE_PRO_GUITAR; break; } - case OG_XBOX: { - OGXboxGamepad_Data_t *report = (OGXboxGamepad_Data_t *)data; - usb_host_data->a |= report->a > 0x20; - usb_host_data->b |= report->b > 0x20; - usb_host_data->x |= report->x > 0x20; - usb_host_data->y |= report->y > 0x20; - usb_host_data->leftShoulder |= report->leftShoulder > 0x20; - usb_host_data->rightShoulder |= report->rightShoulder > 0x20; + // Any other subtypes we dont handle can just be read like gamepads. + default: + { + XInputGamepad_Data_t *report = (XInputGamepad_Data_t *)data; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; usb_host_data->back |= report->back; usb_host_data->start |= report->start; + usb_host_data->guide |= report->guide; usb_host_data->leftThumbClick |= report->leftThumbClick; usb_host_data->rightThumbClick |= report->rightThumbClick; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - if (report->leftTrigger) { + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + if (report->leftTrigger) + { usb_host_data->leftTrigger = report->leftTrigger << 8; } - if (report->rightTrigger) { + if (report->rightTrigger) + { usb_host_data->rightTrigger = report->rightTrigger << 8; } - if (report->leftStickX) { + if (report->leftStickX) + { usb_host_data->leftStickX = report->leftStickX; } - if (report->leftStickY) { + if (report->leftStickY) + { usb_host_data->leftStickY = report->leftStickY; } - if (report->rightStickX) { + if (report->rightStickX) + { usb_host_data->rightStickX = report->rightStickX; } - if (report->rightStickY) { + if (report->rightStickY) + { usb_host_data->rightStickY = report->rightStickY; } - if (report->leftShoulder) { - usb_host_data->pressureL1 = report->leftShoulder; + break; + } + } + break; + } + case XBOXONE: + { + usb_host_data->guide |= device_type.xone_guide; + switch (device_type.sub_type) + { + case GAMEPAD: + { + XboxOneGamepad_Data_t *report = (XboxOneGamepad_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->leftShoulder |= report->leftShoulder; + usb_host_data->green |= report->a; + usb_host_data->red |= report->b; + usb_host_data->yellow |= report->y; + usb_host_data->blue |= report->x; + usb_host_data->orange |= report->leftShoulder; + usb_host_data->rightShoulder |= report->rightShoulder; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->leftThumbClick |= report->leftThumbClick; + usb_host_data->rightThumbClick |= report->rightThumbClick; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + // XB1 reports range from 0 - 1024 + if (report->leftTrigger) + { + usb_host_data->leftTrigger = report->leftTrigger << 6; } - if (report->rightShoulder) { - usb_host_data->pressureR1 = report->rightShoulder; + if (report->rightTrigger) + { + usb_host_data->rightTrigger = report->rightTrigger << 6; } - if (report->y) { - usb_host_data->pressureTriangle = report->y; + if (report->leftStickX) + { + usb_host_data->leftStickX = report->leftStickX; } - if (report->b) { - usb_host_data->pressureCircle = report->b; + if (report->leftStickY) + { + usb_host_data->leftStickY = report->leftStickY; } - if (report->a) { - usb_host_data->pressureCross = report->a; + if (report->rightStickX) + { + usb_host_data->rightStickX = report->rightStickX; } - if (report->x) { - usb_host_data->pressureSquare = report->x; + if (report->rightStickY) + { + usb_host_data->rightStickY = report->rightStickY; } break; } - case XBOX360_BB: { - XInputBigButton_Data_t *report = (XInputBigButton_Data_t *)data; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; + case ROCK_BAND_GUITAR: + { + XboxOneRockBandGuitar_Data_t *report = (XboxOneRockBandGuitar_Data_t *)data; usb_host_data->a |= report->a; usb_host_data->b |= report->b; usb_host_data->x |= report->x; usb_host_data->y |= report->y; usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; usb_host_data->back |= report->back; usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->rightThumbClick |= report->rightThumbClick; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - break; - } - - case XINPUTCOMPAT: { - XInputCompatGamepad_Data_t *report = (XInputCompatGamepad_Data_t *)data; - if (report->rid == 2) { - usb_host_data->guide = data[1]; - break; + usb_host_data->green |= report->green; + usb_host_data->red |= report->red; + usb_host_data->yellow |= report->yellow; + usb_host_data->blue |= report->blue; + usb_host_data->orange |= report->orange; + usb_host_data->soloGreen |= report->soloGreen; + usb_host_data->soloRed |= report->soloRed; + usb_host_data->soloYellow |= report->soloYellow; + usb_host_data->soloBlue |= report->soloBlue; + usb_host_data->soloOrange |= report->soloOrange; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + if (report->tilt) + { + usb_host_data->tilt = report->tilt << 7; } - if (report->rid == 1) { - uint8_t dpad = report->dpad - 1; - usb_host_data->dpadLeft = dpad == 6 || dpad == 5 || dpad == 7; - usb_host_data->dpadRight = dpad == 3 || dpad == 2 || dpad == 1; - usb_host_data->dpadUp = dpad == 0 || dpad == 1 || dpad == 7; - usb_host_data->dpadDown = dpad == 5 || dpad == 4 || dpad == 3; - // Festival pro mode mappings - usb_host_data->green |= dpad == 6 || dpad == 5 || dpad == 7; - usb_host_data->red |= dpad == 0 || dpad == 1 || dpad == 7; - usb_host_data->yellow |= report->x; - usb_host_data->blue |= report->y; - usb_host_data->orange |= report->b; - // Festival expert mappings - // usb_host_data->green |= dpad == 6 || dpad == 5 || dpad == 7; - // usb_host_data->red |= dpad == 3 || dpad == 2 || dpad == 1; - // usb_host_data->yellow |= report->x; - // usb_host_data->blue |= report->y; - // usb_host_data->orange |= report->b; - - // Festival easy/med/hard mappings - // usb_host_data->green |= dpad == 6 || dpad == 5 || dpad == 7; - // usb_host_data->red |= dpad == 3 || dpad == 2 || dpad == 1; - // usb_host_data->yellow |= report->x; - // usb_host_data->blue |= report->b; - // usb_host_data->orange |= report->y; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->rightThumbClick |= report->rightThumbClick; - if (report->leftTrigger) { - usb_host_data->leftTrigger = report->leftTrigger << 6; - } - if (report->rightTrigger) { - usb_host_data->rightTrigger = report->rightTrigger << 6; - } - if (report->leftStickX) { - usb_host_data->leftStickX = report->leftStickX - INT16_MAX; - } - if (report->leftStickY) { - usb_host_data->leftStickY = -(report->leftStickY - INT16_MAX); - } - if (report->rightStickX) { - usb_host_data->rightStickX = report->rightStickX - INT16_MAX; - } - if (report->rightStickY) { - usb_host_data->rightStickY = -(report->rightStickY - INT16_MAX); - } + if (report->whammy) + { + usb_host_data->whammy = report->whammy; } - break; - } - case XBOX360_W: - case XBOX360: { - switch (device_type.sub_type) { - case XINPUT_GUITAR_BASS: - case XINPUT_GUITAR: { - XInputRockBandGuitar_Data_t *report = (XInputRockBandGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - if (report->tilt) { - usb_host_data->tilt = INT16_MAX; - } - if (report->solo) { - usb_host_data->soloGreen |= report->a; - usb_host_data->soloRed |= report->b; - usb_host_data->soloYellow |= report->y; - usb_host_data->soloBlue |= report->x; - usb_host_data->soloOrange |= report->leftShoulder; - } - if (report->whammy) { - usb_host_data->whammy = (report->whammy >> 8) - PS3_STICK_CENTER; - } - if (report->pickup) { - usb_host_data->pickup = report->pickup; - } - break; - } - case XINPUT_GUITAR_WT: - case XINPUT_GUITAR_ALTERNATE: { - XInputGuitarHeroGuitar_Data_t *report = (XInputGuitarHeroGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - if (report->tilt) { - usb_host_data->tilt = report->tilt; - } - if (report->whammy) { - usb_host_data->whammy = (report->whammy >> 8) - PS3_STICK_CENTER; - } - - uint8_t slider = (report->slider >> 8) ^ 0x80; - - if (device_type.sub_type == XINPUT_GUITAR_WT) { - if (slider < 0x2F) { - usb_host_data->slider = 0x15; - } else if (slider <= 0x3F) { - usb_host_data->slider = 0x30; - } else if (slider <= 0x5F) { - usb_host_data->slider = 0x4D; - } else if (slider <= 0x6F) { - usb_host_data->slider = 0x66; - } else if (slider <= 0x8F) { - usb_host_data->slider = 0x80; - } else if (slider <= 0x9F) { - usb_host_data->slider = 0x9A; - } else if (slider <= 0xAF) { - usb_host_data->slider = 0xAF; - } else if (slider <= 0xCF) { - usb_host_data->slider = 0xC9; - } else if (slider <= 0xEF) { - usb_host_data->slider = 0xE6; - } else { - usb_host_data->slider = 0xFF; - } - } - break; - } - case XINPUT_RB_DRUMS: { - XInputRockBandDrums_Data_t *report = (XInputRockBandDrums_Data_t *)data; - bool up = report->dpadUp; - bool down = report->dpadDown; - bool left = report->dpadLeft; - bool right = report->dpadRight; - bool kick1 = report->leftShoulder; - bool kick2 = report->leftThumbClick; - - uint8_t redVelocity = xinput_rb_velocity_positive(report->redVelocity); - uint8_t greenVelocity = xinput_rb_velocity_negative(report->greenVelocity); - uint8_t yellowVelocity = xinput_rb_velocity_negative(report->yellowVelocity); - uint8_t blueVelocity = xinput_rb_velocity_positive(report->blueVelocity); - - SET_RB_PADS(); - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - break; - } - case XINPUT_GH_DRUMS: { - XInputGuitarHeroDrums_Data_t *report = (XInputGuitarHeroDrums_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - SET_GH_PADS(); - // Forward any midi data we get - if ((report->midiPacket[0] & 0xF0) == 0x90) { - onNote(report->midiPacket[0] & 0x0F, report->midiPacket[1], report->midiPacket[2]); - } else if ((report->midiPacket[0] & 0xF0) == 0x80) { - offNote(report->midiPacket[0] & 0x0F, report->midiPacket[1], report->midiPacket[2]); - } - break; - } - case XINPUT_GUITAR_HERO_LIVE: { - XInputGHLGuitar_Data_t *report = (XInputGHLGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - if (report->tilt) { - usb_host_data->tilt = report->tilt; - } - if (report->whammy) { - usb_host_data->whammy = report->whammy; - } - break; - } - case XINPUT_TURNTABLE: { - XInputTurntable_Data_t *report = (XInputTurntable_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftBlue |= report->leftBlue; - usb_host_data->leftRed |= report->leftRed; - usb_host_data->leftGreen |= report->leftGreen; - usb_host_data->rightBlue |= report->rightBlue; - usb_host_data->rightRed |= report->rightRed; - usb_host_data->rightGreen |= report->rightGreen; - if (report->effectsKnob) { - usb_host_data->effectsKnob = report->effectsKnob; - } - if (report->crossfader) { - usb_host_data->crossfader = report->crossfader; - } - if (report->leftTableVelocity) { - if (report->leftTableVelocity > 127) { - report->leftTableVelocity = 127; - } - if (report->leftTableVelocity < -127) { - report->leftTableVelocity = -127; - } - usb_host_data->leftTableVelocity = report->leftTableVelocity << 8; - } - if (report->rightTableVelocity) { - if (report->rightTableVelocity > 127) { - report->rightTableVelocity = 127; - } - if (report->rightTableVelocity < -127) { - report->rightTableVelocity = -127; - } - usb_host_data->rightTableVelocity = report->rightTableVelocity << 8; - } - break; - } - case XINPUT_PRO_KEYS: { - XInputRockBandKeyboard_Data_t *report = (XInputRockBandKeyboard_Data_t *)data; - usb_host_data->dpadLeft |= report->dpadLeft; - usb_host_data->dpadRight |= report->dpadRight; - usb_host_data->dpadUp |= report->dpadUp; - usb_host_data->dpadDown |= report->dpadDown; - - TRANSLATE_PRO_KEYS; - break; - } - case XINPUT_PRO_GUITAR: { - XInputRockBandProGuitar_Data_t *report = (XInputRockBandProGuitar_Data_t *)data; - usb_host_data->dpadLeft |= report->dpadLeft; - usb_host_data->dpadRight |= report->dpadRight; - usb_host_data->dpadUp |= report->dpadUp; - usb_host_data->dpadDown |= report->dpadDown; - TRANSLATE_PRO_GUITAR; - break; - } - // Any other subtypes we dont handle can just be read like gamepads. - default: { - XInputGamepad_Data_t *report = (XInputGamepad_Data_t *)data; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->rightThumbClick |= report->rightThumbClick; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - if (report->leftTrigger) { - usb_host_data->leftTrigger = report->leftTrigger << 8; - } - if (report->rightTrigger) { - usb_host_data->rightTrigger = report->rightTrigger << 8; - } - if (report->leftStickX) { - usb_host_data->leftStickX = report->leftStickX; - } - if (report->leftStickY) { - usb_host_data->leftStickY = report->leftStickY; - } - if (report->rightStickX) { - usb_host_data->rightStickX = report->rightStickX; - } - if (report->rightStickY) { - usb_host_data->rightStickY = report->rightStickY; - } - break; - } + if (report->pickup) + { + usb_host_data->pickup = report->pickup; } break; } - case XBOXONE: { - switch (device_type.sub_type) { - case GAMEPAD: { - XboxOneGamepad_Data_t *report = (XboxOneGamepad_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->green |= report->a; - usb_host_data->red |= report->b; - usb_host_data->yellow |= report->y; - usb_host_data->blue |= report->x; - usb_host_data->orange |= report->leftShoulder; - usb_host_data->rightShoulder |= report->rightShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->leftThumbClick |= report->leftThumbClick; - usb_host_data->rightThumbClick |= report->rightThumbClick; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - // XB1 reports range from 0 - 1024 - if (report->leftTrigger) { - usb_host_data->leftTrigger = report->leftTrigger << 6; - } - if (report->rightTrigger) { - usb_host_data->rightTrigger = report->rightTrigger << 6; - } - if (report->leftStickX) { - usb_host_data->leftStickX = report->leftStickX; - } - if (report->leftStickY) { - usb_host_data->leftStickY = report->leftStickY; - } - if (report->rightStickX) { - usb_host_data->rightStickX = report->rightStickX; - } - if (report->rightStickY) { - usb_host_data->rightStickY = report->rightStickY; - } - break; - } - case ROCK_BAND_GUITAR: { - XboxOneRockBandGuitar_Data_t *report = (XboxOneRockBandGuitar_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->leftShoulder |= report->leftShoulder; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->green |= report->green; - usb_host_data->red |= report->red; - usb_host_data->yellow |= report->yellow; - usb_host_data->blue |= report->blue; - usb_host_data->orange |= report->orange; - usb_host_data->soloGreen |= report->soloGreen; - usb_host_data->soloRed |= report->soloRed; - usb_host_data->soloYellow |= report->soloYellow; - usb_host_data->soloBlue |= report->soloBlue; - usb_host_data->soloOrange |= report->soloOrange; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - if (report->tilt) { - usb_host_data->tilt = report->tilt << 8; - } - if (report->whammy) { - usb_host_data->whammy = report->whammy; - } - if (report->pickup) { - usb_host_data->pickup = report->pickup; - } - break; - } - case ROCK_BAND_DRUMS: { - XboxOneRockBandDrums_Data_t *report = (XboxOneRockBandDrums_Data_t *)data; - usb_host_data->a |= report->a; - usb_host_data->b |= report->b; - usb_host_data->x |= report->x; - usb_host_data->y |= report->y; - usb_host_data->back |= report->back; - usb_host_data->start |= report->start; - usb_host_data->guide |= report->guide; - usb_host_data->dpadLeft = report->dpadLeft; - usb_host_data->dpadRight = report->dpadRight; - usb_host_data->dpadUp = report->dpadUp; - usb_host_data->dpadDown = report->dpadDown; - if (report->greenVelocity) { - onNote(10, RB_MIDI_NOTE_GREEN, report->greenVelocity << 3); - } else { - offNote(10, RB_MIDI_NOTE_GREEN, 0); - } - if (report->redVelocity) { - onNote(10, RB_MIDI_NOTE_RED, report->redVelocity << 3); - } else { - offNote(10, RB_MIDI_NOTE_RED, 0); - } - if (report->yellowVelocity) { - onNote(10, RB_MIDI_NOTE_YELLOW, report->redVelocity << 3); - } else { - offNote(10, RB_MIDI_NOTE_YELLOW, 0); - } - if (report->blueVelocity) { - onNote(10, RB_MIDI_NOTE_BLUE, report->redVelocity << 3); - } else { - offNote(10, RB_MIDI_NOTE_BLUE, 0); - } - if (report->blueCymbalVelocity) { - onNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, report->redVelocity << 3); - } else { - offNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, 0); - } - if (report->yellowCymbalVelocity) { - onNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, report->redVelocity << 3); - } else { - offNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, 0); - } - if (report->greenCymbalVelocity) { - onNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, report->redVelocity << 3); - } else { - offNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, 0); - } - if (report->leftShoulder) { - onNote(10, RB_MIDI_NOTE_KICK, 0x7F); - } else { - offNote(10, RB_MIDI_NOTE_KICK, 0); - } - if (report->rightShoulder) { - onNote(10, RB_MIDI_NOTE_KICK2, 0x7F); - } else { - offNote(10, RB_MIDI_NOTE_KICK2, 0); - } - break; - } + case ROCK_BAND_DRUMS: + { + XboxOneRockBandDrums_Data_t *report = (XboxOneRockBandDrums_Data_t *)data; + usb_host_data->a |= report->a; + usb_host_data->b |= report->b; + usb_host_data->x |= report->x; + usb_host_data->y |= report->y; + usb_host_data->back |= report->back; + usb_host_data->start |= report->start; + usb_host_data->dpadLeft |= report->dpadLeft; + usb_host_data->dpadRight |= report->dpadRight; + usb_host_data->dpadUp |= report->dpadUp; + usb_host_data->dpadDown |= report->dpadDown; + if (report->greenVelocity) + { + onNote(10, RB_MIDI_NOTE_GREEN, report->greenVelocity << 3); + } + else + { + offNote(10, RB_MIDI_NOTE_GREEN, 0); + } + if (report->redVelocity) + { + onNote(10, RB_MIDI_NOTE_RED, report->redVelocity << 3); + } + else + { + offNote(10, RB_MIDI_NOTE_RED, 0); + } + if (report->yellowVelocity) + { + onNote(10, RB_MIDI_NOTE_YELLOW, report->redVelocity << 3); + } + else + { + offNote(10, RB_MIDI_NOTE_YELLOW, 0); + } + if (report->blueVelocity) + { + onNote(10, RB_MIDI_NOTE_BLUE, report->redVelocity << 3); + } + else + { + offNote(10, RB_MIDI_NOTE_BLUE, 0); + } + if (report->blueCymbalVelocity) + { + onNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, report->redVelocity << 3); + } + else + { + offNote(10, RB_MIDI_NOTE_BLUE_CYMBAL, 0); + } + if (report->yellowCymbalVelocity) + { + onNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, report->redVelocity << 3); + } + else + { + offNote(10, RB_MIDI_NOTE_YELLOW_CYMBAL, 0); + } + if (report->greenCymbalVelocity) + { + onNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, report->redVelocity << 3); + } + else + { + offNote(10, RB_MIDI_NOTE_GREEN_CYMBAL, 0); + } + if (report->leftShoulder) + { + onNote(10, RB_MIDI_NOTE_KICK, 0x7F); + } + else + { + offNote(10, RB_MIDI_NOTE_KICK, 0); + } + if (report->rightShoulder) + { + onNote(10, RB_MIDI_NOTE_KICK2, 0x7F); + } + else + { + offNote(10, RB_MIDI_NOTE_KICK2, 0); } break; } + } + break; + } } } #ifdef TICK_PS2 PS2_REPORT ps2Report; -void tick_ps2output() { +void tick_ps2output() +{ PS2_REPORT *report = &ps2Report; - if (!ps2_emu_tick(report)) { + if (!ps2_emu_tick(report)) + { return; } uint8_t packet_size = 0; @@ -2158,21 +2793,31 @@ void tick_ps2output() { #include "inputs/mpr121.h" #include "inputs/ps2.h" #include "inputs/slave_tick.h" -#include "inputs/turntable.h" #include "inputs/usb_host.h" #include "inputs/wii.h" #include "inputs/wt_neck.h" +#include "inputs/mustang_neck.h" +#include "inputs/crkd.h" TICK_SHARED; - if (!startedInactivityPulse) { + if (!startedInactivityPulse) + { // check if any inputs are active, and if so set lastInputActivity to now - for (int i = 0; i < DIGITAL_COUNT; i++) { - if (debounce[i]) { + for (int i = 0; i < DIGITAL_COUNT; i++) + { + if (debounce[i]) + { lastInputActivity = millis(); } } } memset(report, 0, sizeof(report)); +#if DEVICE_TYPE == GAMEPAD || DEVICE_TYPE == TAIKO + report->leftStickX = PS3_STICK_CENTER; + report->leftStickY = PS3_STICK_CENTER; + report->rightStickX = PS3_STICK_CENTER; + report->rightStickY = PS3_STICK_CENTER; +#endif #if DEVICE_TYPE_IS_GUITAR report->dpadLeft = true; report->whammy = 0x7f; @@ -2182,22 +2827,27 @@ void tick_ps2output() { } #endif #ifdef TICK_WII -void tick_wiioutput() { +void tick_wiioutput() +{ #include "inputs/accel.h" #include "inputs/clone_neck.h" #include "inputs/gh5_neck.h" #include "inputs/mpr121.h" #include "inputs/ps2.h" #include "inputs/slave_tick.h" -#include "inputs/turntable.h" #include "inputs/usb_host.h" #include "inputs/wii.h" #include "inputs/wt_neck.h" +#include "inputs/mustang_neck.h" +#include "inputs/turntable.h" TICK_SHARED; - if (!startedInactivityPulse) { + if (!startedInactivityPulse) + { // check if any inputs are active, and if so set lastInputActivity to now - for (int i = 0; i < DIGITAL_COUNT; i++) { - if (debounce[i]) { + for (int i = 0; i < DIGITAL_COUNT; i++) + { + if (debounce[i]) + { lastInputActivity = millis(); } } @@ -2266,9 +2916,12 @@ void tick_wiioutput() { report->buttonsLow = ~report->buttonsLow; report->buttonsHigh = ~report->buttonsHigh; uint8_t format = wii_data_format(); - if (format == 3) { + if (format == 3) + { memcpy(wii_data, report, sizeof(report)); - } else if (format == 2) { + } + else if (format == 2) + { WiiClassicDataFormat2_t *real_report = (WiiClassicDataFormat2_t *)wii_data; real_report->buttonsLow = report->buttonsLow; real_report->buttonsHigh = report->buttonsHigh; @@ -2278,7 +2931,9 @@ void tick_wiioutput() { real_report->rightStickY92 = report->rightStickY; real_report->leftTrigger = report->leftTrigger; real_report->rightTrigger = report->rightTrigger; - } else if (format == 1) { + } + else if (format == 1) + { // Similar to the turntable, classic format 1 is awful so we need to translate to an intermediate format first WiiIntermediateClassicDataFormat_t intermediate_report; intermediate_report.rightStickX = report->rightStickX >> 3; @@ -2299,44 +2954,81 @@ void tick_wiioutput() { #endif } #endif -void bluetooth_connected() { +void bluetooth_connected() +{ input_start = millis(); } uint8_t rbcount = 0; uint8_t lastrbcount = 0; -uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t output_console_type) { +uint8_t hadCymbal = 0; +bool greenCymbal; +bool greenPad; +bool yellowCymbal; +bool blueCymbal; +long lastCymbalOff = 0; +long lastGreenOff = 0; +uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t output_console_type) +{ uint8_t packet_size = 0; Buffer_Report_t current_queue_report = {val : 0}; bool drumHit = false; #if DIGITAL_COUNT bool drumSeen[DIGITAL_COUNT] = {false}; #endif + if (INPUT_QUEUE) + { + if (micros() - last_queue > 100) + { + last_queue = micros(); + for (int i = 0; i < DIGITAL_COUNT; i++) + { + if (debounce[i]) + { + debounce[i]--; + } + } +#if REQUIRE_LED_DEBOUNCE + for (int i = 0; i < LED_DEBOUNCE_COUNT; i++) + { + if (ledDebounce[i]) + { + ledDebounce[i]--; + } + } +#endif + } + } // Tick Inputs #include "inputs/accel.h" +#include "inputs/bh_drum.h" #include "inputs/clone_neck.h" #include "inputs/gh5_neck.h" -#include "inputs/bh_drum.h" #include "inputs/mpr121.h" #include "inputs/ps2.h" #include "inputs/slave_tick.h" -#include "inputs/turntable.h" #include "inputs/usb_host.h" #include "inputs/wii.h" -#include "inputs/wt_neck.h" #include "inputs/wt_drum.h" - +#include "inputs/wt_neck.h" +#include "inputs/mustang_neck.h" +#include "inputs/crkd.h" +#include "inputs/turntable.h" TICK_SHARED; - if (!startedInactivityPulse) { + if (!startedInactivityPulse) + { // check if any inputs are active, and if so set lastInputActivity to now - for (int i = 0; i < DIGITAL_COUNT; i++) { - if (debounce[i]) { + for (int i = 0; i < DIGITAL_COUNT; i++) + { + if (debounce[i]) + { lastInputActivity = millis(); } } } // give the user 2 second to jump between modes (aka, hold on plug in) - if ((millis() - input_start) < 2000 && (millis() - input_start) > 100) { + if ((millis() - input_start) < 2000 && (millis() - input_start) > 100) + { TICK_DETECTION; } #ifdef TICK_DETECTION_FESTIVAL @@ -2344,36 +3036,26 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu #endif // We tick the guitar every 5ms to handle inputs if nothing is attempting to read, but this doesn't need to output that data anywhere. // if input queues are enabled, then we just tick as often as possible - if (!buf) { - if (INPUT_QUEUE) { - if (micros() - last_queue > 100) { - last_queue = micros(); - for (int i = 0; i < DIGITAL_COUNT; i++) { - if (debounce[i]) { - debounce[i]--; - } - } -#if REQUIRE_LED_DEBOUNCE - for (int i = 0; i < LED_DEBOUNCE_COUNT; i++) { - if (ledDebounce[i]) { - ledDebounce[i]--; - } - } -#endif - } - if (current_queue_report.val != last_queue_report.val) { - queue[queue_tail] = current_queue_report; - last_queue_report = current_queue_report; - if (queue_size < BUFFER_SIZE_QUEUE) { - queue_size++; - queue_tail++; - } + if (INPUT_QUEUE) + { + if (current_queue_report.val != last_queue_report.val) + { + queue[queue_tail] = current_queue_report; + last_queue_report = current_queue_report; + if (queue_size < BUFFER_SIZE_QUEUE) + { + queue_size++; + queue_tail++; } } + } + if (!buf) + { return 0; } - if (INPUT_QUEUE && queue_size) { + if (INPUT_QUEUE && queue_size) + { current_queue_report = queue[queue_tail - queue_size]; queue_size--; } @@ -2382,73 +3064,88 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu // Then mouse, as it is an axis so it is more likley to have changes #if defined(TICK_NKRO) || defined(TICK_SIXKRO) #if !DEVICE_TYPE_IS_KEYBOARD - if (consoleType == KEYBOARD_MOUSE) { + if (consoleType == KEYBOARD_MOUSE) + { #endif void *lastReportToCheck; - for (int i = 1; i < REPORT_ID_END; i++) { + for (int i = 1; i < REPORT_ID_END; i++) + { #ifdef TICK_MOUSE - if (i == REPORT_ID_MOUSE) { + if (i == REPORT_ID_MOUSE) + { packet_size = sizeof(USB_Mouse_Data_t); memset(buf, 0, packet_size); USB_Mouse_Data_t *report = (USB_Mouse_Data_t *)buf; report->rid = REPORT_ID_MOUSE; TICK_MOUSE; - if (last_report) { + if (last_report) + { lastReportToCheck = &last_report->lastMouseReport; } } #endif #ifdef TICK_CONSUMER - if (i == REPORT_ID_CONSUMER) { + if (i == REPORT_ID_CONSUMER) + { packet_size = sizeof(USB_ConsumerControl_Data_t); memset(buf, 0, packet_size); USB_ConsumerControl_Data_t *report = (USB_ConsumerControl_Data_t *)buf; report->rid = REPORT_ID_CONSUMER; TICK_CONSUMER; - if (last_report) { + if (last_report) + { lastReportToCheck = &last_report->lastConsumerReport; } } #endif #ifdef TICK_NKRO - if (i == REPORT_ID_NKRO) { + if (i == REPORT_ID_NKRO) + { packet_size = sizeof(USB_NKRO_Data_t); memset(buf, 0, packet_size); USB_NKRO_Data_t *report = (USB_NKRO_Data_t *)buf; report->rid = REPORT_ID_NKRO; TICK_NKRO; - if (last_report) { + if (last_report) + { lastReportToCheck = &last_report->lastNKROReport; } } #endif #ifdef TICK_SIXKRO - if (i == REPORT_ID_NKRO) { + if (i == REPORT_ID_NKRO) + { packet_size = sizeof(USB_6KRO_Data_t); memset(buf, 0, packet_size); USB_6KRO_Data_t *report = (USB_6KRO_Data_t *)buf; report->rid = REPORT_ID_NKRO; TICK_SIXKRO; - if (last_report) { + if (last_report) + { lastReportToCheck = &last_report->last6KROReport; } } #endif // If we are directly asked for a HID report, always just reply with the NKRO one - if (lastReportToCheck && output_console_type != BLUETOOTH_REPORT) { + if (lastReportToCheck && output_console_type != BLUETOOTH_REPORT) + { uint8_t cmp = memcmp(lastReportToCheck, buf, packet_size); - if (cmp == 0) { + if (cmp == 0) + { packet_size = 0; continue; } memcpy(lastReportToCheck, buf, packet_size); break; - } else { + } + else + { break; } } - if (packet_size) { + if (packet_size) + { return packet_size; } #endif @@ -2462,8 +3159,8 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu bool updateHIDSequence = false; uint8_t proKeyVelocities[25] = {0}; memset(proKeyVelocities, 0, sizeof(proKeyVelocities)); -#if USB_HOST_STACK - if (output_console_type == XBOXONE) { + if (output_console_type == XBOXONE) + { XBOX_ONE_REPORT *report = (XBOX_ONE_REPORT *)buf; #if DEVICE_TYPE_IS_LIVE_GUITAR XboxOneGHLGuitarWithGamepad_Data_t *reportGHL = (XboxOneGHLGuitarWithGamepad_Data_t *)buf; @@ -2475,12 +3172,19 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu packet_size = sizeof(XBOX_ONE_REPORT); report_size = packet_size - sizeof(GipHeader_t); memset(buf, 0, packet_size); + asm volatile("" :: + : "memory"); +#if DEVICE_TYPE == ROCK_BAND_GUITAR || DEVICE_TYPE == GUITAR_HERO_GUITAR + report->joystickX = 0; + report->joystickY = 0; +#endif GIP_HEADER(report, GIP_INPUT_REPORT, false, report_sequence_number); TICK_XBOX_ONE; asm volatile("" :: : "memory"); - if (report->guide != lastXboxOneGuide) { + if (report->guide != lastXboxOneGuide) + { lastXboxOneGuide = report->guide; GipKeystroke_t *keystroke = (GipKeystroke_t *)buf; GIP_HEADER(keystroke, GIP_VIRTUAL_KEYCODE, true, keystroke_sequence_number++); @@ -2493,10 +3197,12 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu GipPacket_t *packet = (GipPacket_t *)report; report_data = (USB_Report_Data_t *)packet->data; updateSequence = true; + #if DEVICE_TYPE_IS_LIVE_GUITAR packet_size = sizeof(XboxOneGHLGuitarWithGamepad_Data_t); uint8_t cmp = memcmp(last_report, report_data, report_size); - if (cmp == 0) { + if (cmp == 0) + { // gamepad report has not changed, so only send GHL report packet_size = sizeof(XboxOneGHLGuitar_Data_t); updateSequence = false; @@ -2507,8 +3213,8 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu updateHIDSequence = true; #endif } -#endif - if (output_console_type == OG_XBOX) { + if (output_console_type == OG_XBOX) + { OG_XBOX_REPORT *report = (OG_XBOX_REPORT *)report_data; memset(report_data, 0, sizeof(OG_XBOX_REPORT)); report->rid = 0; @@ -2520,7 +3226,8 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu TICK_OG_XBOX; report_size = packet_size = sizeof(OG_XBOX_REPORT); } - if (output_console_type == WINDOWS || output_console_type == XBOX360) { + if (output_console_type == WINDOWS || output_console_type == XBOX360) + { XINPUT_REPORT *report = (XINPUT_REPORT *)report_data; memset(report_data, 0, sizeof(XINPUT_REPORT)); report->rid = 0; @@ -2529,11 +3236,18 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu #if DEVICE_TYPE_IS_GUITAR || DEVICE_TYPE_IS_LIVE_GUITAR report->whammy = INT16_MIN; #endif - +#if DEVICE_TYPE == ROCK_BAND_DRUMS + // rb drums have some weird logic so this is what we need to send when nothing is hit + report->redVelocity = -1; + report->blueVelocity = -1; + report->greenVelocity = 0; + report->yellowVelocity = 0; +#endif TICK_XINPUT; #if DEVICE_TYPE == GUITAR_HERO_GUITAR - if (seen_rpcs3) { + if (seen_rpcs3) + { report->whammy = (INT16_MAX + (uint32_t)(report->whammy)) >> 1; } #endif @@ -2542,6 +3256,72 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu #endif #if PRO_GUITAR && BLUETOOTH_RX TRANSLATE_TO_PRO_GUITAR(bt_data) +#endif +#ifdef MUSTANG_NECK_SPI_PORT + report->lowEFret = lastProtar.lowEFret; + report->aFret = lastProtar.aFret; + report->dFret = lastProtar.dFret; + report->gFret = lastProtar.gFret; + report->bFret = lastProtar.bFret; + report->highEFret = lastProtar.highEFret; + report->green = lastProtar.green; + report->red = lastProtar.red; + report->yellow = lastProtar.yellow; + report->blue = lastProtar.blue; + report->orange = lastProtar.orange; + report->soloFlag = lastProtar.soloFlag; +#endif + +#if DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_MUSTANG || DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_SQUIRE + if (midiData.seenProGuitar) + { + report->lowEFretVelocity = midiData.midiStringVelocities[5]; + report->aFretVelocity = midiData.midiStringVelocities[4]; + report->dFretVelocity = midiData.midiStringVelocities[3]; + report->gFretVelocity = midiData.midiStringVelocities[2]; + report->bFretVelocity = midiData.midiStringVelocities[1]; + report->highEFretVelocity = midiData.midiStringVelocities[0]; + report->tilt = midiData.proGuitarData.tilt ? 0x7F : 0x40; + report->start |= midiData.proGuitarData.start; + report->back |= midiData.proGuitarData.back; + report->guide |= midiData.proGuitarData.guide; +#if DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_SQUIRE + report->guide |= midiData.proGuitarData.start && midiData.proGuitarData.back; +#endif + report->a |= midiData.proGuitarData.a; + report->b |= midiData.proGuitarData.b; + report->x |= midiData.proGuitarData.x; + report->y |= midiData.proGuitarData.y; + + uint8_t dpad = midiData.proGuitarData.dpad; + dpad = dpad >= 0x08 ? 0 : dpad_bindings_reverse[dpad]; + asm volatile("" :: + : "memory"); + report->dpadUp |= (dpad & UP) != 0; + report->dpadLeft |= (dpad & LEFT) != 0; + report->dpadDown |= (dpad & DOWN) != 0; + report->dpadRight |= (dpad & RIGHT) != 0; + for (size_t i = 0; i < TU_ARRAY_SIZE(midiData.midiFrets); i++) + { + uint8_t fret = midiData.midiFrets[i]; + report->green |= fret == 1 || fret == 6 || fret == 13; + report->red |= fret == 2 || fret == 7 || fret == 14; + report->yellow |= fret == 3 || fret == 8 || fret == 15; + report->blue |= fret == 4 || fret == 9 || fret == 16; + report->orange |= fret == 5 || fret == 10 || fret == 17; + report->solo |= fret >= 13 && fret <= 17; + } + report->lowEFret = midiData.midiFrets[5]; + report->aFret = midiData.midiFrets[4]; + report->dFret = midiData.midiFrets[3]; + report->gFret = midiData.midiFrets[2]; + report->bFret = midiData.midiFrets[1]; + report->highEFret = midiData.midiFrets[0]; + } +#endif +#if PRO_GUITAR + report->autoCal_Light = report->tilt; + report->autoCal_Microphone = report->tilt; #endif asm volatile("" :: : "memory"); @@ -2549,8 +3329,10 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu #if DEVICE_TYPE == ROCK_BAND_PRO_KEYS bool key25 = report->key25; uint8_t currentVel = 0; - for (int i = 0; i < sizeof(proKeyVelocities) && currentVel <= 4; i++) { - if (proKeyVelocities[i]) { + for (int i = 0; i < sizeof(proKeyVelocities) && currentVel <= 4; i++) + { + if (proKeyVelocities[i]) + { report->velocities[currentVel] = proKeyVelocities[i] >> 1; currentVel++; } @@ -2562,12 +3344,32 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu report->leftThumbClick = true; #endif report_size = packet_size = sizeof(XINPUT_REPORT); +#if DEVICE_TYPE == ROCK_BAND_DRUMS + if (!report->cymbalFlag && ready_for_next_packet() && (greenCymbal || yellowCymbal || blueCymbal)) + { + if (greenCymbal) + { + lastGreenOff = millis(); + } + greenCymbal = false; + yellowCymbal = false; + blueCymbal = false; + lastCymbalOff = millis(); + } + if (!report->padFlag && ready_for_next_packet() && greenPad) + { + greenPad = false; + lastGreenOff = millis(); + } +#endif } // Guitars and Drums can fall back to their PS3 versions, so don't even include the PS4 version there. // DJ Hero was never on ps4, so we can't really implement that either, so just fall back to PS3 there too. #if SUPPORTS_PS4 - if (output_console_type == PS4 || output_console_type == IOS_FESTIVAL) { - if (millis() > 450000 && !auth_ps4_controller_found) { + if (output_console_type == PS4) + { + if (millis() > 450000 && !auth_ps4_controller_found) + { reset_usb(); } PS4_REPORT *report = (PS4_REPORT *)report_data; @@ -2579,26 +3381,63 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu gamepad->rightStickX = PS3_STICK_CENTER; gamepad->rightStickY = PS3_STICK_CENTER; // PS4 does not start using the controller until it sees a PS button press. - if (!seen_ps4_console) { + if (!report_requested) + { report->guide = true; } TICK_PS4; - -#if PRO_GUITAR && USB_HOST_STACK - TRANSLATE_TO_PRO_GUITAR(usb_host_data) -#endif -#if PRO_GUITAR && BLUETOOTH_RX - TRANSLATE_TO_PRO_GUITAR(bt_data) -#endif asm volatile("" :: : "memory"); gamepad->dpad = (gamepad->dpad & 0xf) > 0x0a ? 0x08 : dpad_bindings[gamepad->dpad]; report_size = packet_size = sizeof(PS4_REPORT); } + if (output_console_type == PS5) + { + if (millis() > 450000 && !auth_ps4_controller_found) + { + reset_usb(); + } + PS5_REPORT *report = (PS5_REPORT *)report_data; + memset(report, 0, sizeof(PS5_REPORT)); + PS5Dpad_Data_t *gamepad = (PS5Dpad_Data_t *)report; + gamepad->report_id = 0x01; + gamepad->leftStickX = PS3_STICK_CENTER; + gamepad->leftStickY = PS3_STICK_CENTER; + gamepad->rightStickX = PS3_STICK_CENTER; + gamepad->rightStickY = PS3_STICK_CENTER; + gamepad->data_30_31_0x001a = 0x001a; + // PS5 does not start using the controller until it sees a PS button press. + TICK_PS4; + if (!report_requested) + { + gamepad->guide = true; + } + asm volatile("" :: + : "memory"); + gamepad->dpad = (gamepad->dpad & 0xf) > 0x0a ? 0x08 : dpad_bindings[gamepad->dpad]; + report_size = packet_size = sizeof(PS5_REPORT); + } #endif #ifdef TICK_FESTIVAL - if (output_console_type == IOS_FESTIVAL) { - if (!festival_gameplay_mode) { + if (output_console_type == IOS_FESTIVAL) + { + if (!festival_gameplay_mode) + { +#if DEVICE_TYPE_IS_DRUM + PS3GamepadDrum_Data_t *report = (PS3GamepadDrum_Data_t *)report_data; + memset(report, 0, sizeof(PS3GamepadDrum_Data_t)); + report->reportId = 1; + report->accelX = PS3_ACCEL_CENTER; + report->accelY = PS3_ACCEL_CENTER; + report->accelZ = PS3_ACCEL_CENTER; + report->gyro = PS3_ACCEL_CENTER; + report->leftStickX = PS3_STICK_CENTER; + report->leftStickY = PS3_STICK_CENTER; + report->rightStickX = PS3_STICK_CENTER; + report->rightStickY = PS3_STICK_CENTER; + TICK_PS3_WITHOUT_CAPTURE; + report_size = packet_size = sizeof(PS3GamepadDrum_Data_t); +#else PS3GamepadGuitar_Data_t *report = (PS3GamepadGuitar_Data_t *)report_data; memset(report, 0, sizeof(PS3GamepadGuitar_Data_t)); report->reportId = 1; @@ -2612,7 +3451,22 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu report->rightStickY = PS3_STICK_CENTER; TICK_PS3_WITHOUT_CAPTURE; report_size = packet_size = sizeof(PS3GamepadGuitar_Data_t); - } else { +#endif + } + else + { + +#if DEVICE_TYPE_IS_DRUM + PS3FestivalProDrumLayer_Data_t *report = (PS3FestivalProDrumLayer_Data_t *)report_data; + memset(report, 0, sizeof(PS3FestivalProDrumLayer_Data_t)); + report->reportId = 0x01; + report->leftStickX = PS3_STICK_CENTER; + report->leftStickY = PS3_STICK_CENTER; + report->rightStickX = PS3_STICK_CENTER; + report->rightStickY = PS3_STICK_CENTER; + TICK_FESTIVAL; + report_size = packet_size = sizeof(PS3FestivalProDrumLayer_Data_t); +#else PS3FestivalProGuitarLayer_Data_t *report = (PS3FestivalProGuitarLayer_Data_t *)report_data; memset(report, 0, sizeof(PS3FestivalProGuitarLayer_Data_t)); report->reportId = 0x01; @@ -2622,12 +3476,15 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu report->rightStickY = PS3_STICK_CENTER; TICK_FESTIVAL; report_size = packet_size = sizeof(PS3FestivalProGuitarLayer_Data_t); +#endif } } #endif - if (output_console_type == BLUETOOTH_REPORT || output_console_type == UNIVERSAL) { + if (output_console_type == BLUETOOTH_REPORT || output_console_type == UNIVERSAL) + { #ifdef TICK_FESTIVAL - if (!festival_gameplay_mode) { + if (!festival_gameplay_mode) + { #endif PC_REPORT *report = (PC_REPORT *)report_data; report_size = packet_size = sizeof(PC_REPORT); @@ -2657,7 +3514,8 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu report->reportId = 1; TICK_PC; #if DEVICE_TYPE == GUITAR_HERO_GUITAR - if (seen_rpcs3) { + if (seen_rpcs3) + { report->whammy = PS3_STICK_CENTER + (report->whammy >> 1); } #endif @@ -2665,14 +3523,89 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu #if PRO_GUITAR && USB_HOST_STACK TRANSLATE_TO_PRO_GUITAR(usb_host_data) #endif + #if PRO_GUITAR && BLUETOOTH_RX TRANSLATE_TO_PRO_GUITAR(bt_data) +#endif +#ifdef MUSTANG_NECK_SPI_PORT + report->lowEFret = lastProtar.lowEFret; + report->aFret = lastProtar.aFret; + report->dFret = lastProtar.dFret; + report->gFret = lastProtar.gFret; + report->bFret = lastProtar.bFret; + report->highEFret = lastProtar.highEFret; + report->green = lastProtar.green; + report->red = lastProtar.red; + report->yellow = lastProtar.yellow; + report->blue = lastProtar.blue; + report->orange = lastProtar.orange; +#endif +#if DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_MUSTANG || DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_SQUIRE + if (midiData.seenProGuitar) + { + report->lowEFretVelocity = midiData.midiStringVelocities[5]; + report->aFretVelocity = midiData.midiStringVelocities[4]; + report->dFretVelocity = midiData.midiStringVelocities[3]; + report->gFretVelocity = midiData.midiStringVelocities[2]; + report->bFretVelocity = midiData.midiStringVelocities[1]; + report->highEFretVelocity = midiData.midiStringVelocities[0]; + report->tilt = midiData.proGuitarData.tilt ? 0x7F : 0x40; + report->start |= midiData.proGuitarData.start; + report->back |= midiData.proGuitarData.back; + report->guide |= midiData.proGuitarData.guide; +#if DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_SQUIRE + report->guide |= midiData.proGuitarData.start && midiData.proGuitarData.back; +#endif + report->a |= midiData.proGuitarData.a; + report->b |= midiData.proGuitarData.b; + report->x |= midiData.proGuitarData.x; + report->y |= midiData.proGuitarData.y; + + uint8_t dpad = midiData.proGuitarData.dpad; + dpad = dpad >= 0x08 ? 0 : dpad_bindings_reverse[dpad]; + asm volatile("" :: + : "memory"); + report->dpadUp |= (dpad & UP) != 0; + report->dpadLeft |= (dpad & LEFT) != 0; + report->dpadDown |= (dpad & DOWN) != 0; + report->dpadRight |= (dpad & RIGHT) != 0; + for (size_t i = 0; i < TU_ARRAY_SIZE(midiData.midiFrets); i++) + { + uint8_t fret = midiData.midiFrets[i]; + report->green |= fret == 1 || fret == 6 || fret == 13; + report->red |= fret == 2 || fret == 7 || fret == 14; + report->yellow |= fret == 3 || fret == 8 || fret == 15; + report->blue |= fret == 4 || fret == 9 || fret == 16; + report->orange |= fret == 5 || fret == 10 || fret == 17; + // report->soloFlag |= fret >= 13 && fret <= 17; + } + report->lowEFret = midiData.midiFrets[5]; + report->aFret = midiData.midiFrets[4]; + report->dFret = midiData.midiFrets[3]; + report->gFret = midiData.midiFrets[2]; + report->bFret = midiData.midiFrets[1]; + report->highEFret = midiData.midiFrets[0]; + } #endif asm volatile("" :: : "memory"); report->dpad = (report->dpad & 0xf) > 0x0a ? 0x08 : dpad_bindings[report->dpad]; #ifdef TICK_FESTIVAL - } else { + } + else + { +#if DEVICE_TYPE_IS_DRUM + + PC_FESTIVAL_REPORT *report = (PC_FESTIVAL_REPORT *)report_data; + report_size = packet_size = sizeof(PC_FESTIVAL_REPORT); + memset(report, 0, sizeof(PC_FESTIVAL_REPORT)); + report->reportId = 1; + TICK_FESTIVAL; + + asm volatile("" :: + : "memory"); + report->dpad = (report->dpad & 0xf) > 0x0a ? 0x08 : dpad_bindings[report->dpad]; +#else PC_FESTIVAL_REPORT *report = (PC_FESTIVAL_REPORT *)report_data; report_size = packet_size = sizeof(PC_FESTIVAL_REPORT); memset(report, 0, sizeof(PC_FESTIVAL_REPORT)); @@ -2685,12 +3618,14 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu asm volatile("" :: : "memory"); report->dpad = (report->dpad & 0xf) > 0x0a ? 0x08 : dpad_bindings[report->dpad]; +#endif } #endif } #if DEVICE_TYPE_IS_GUITAR - if (output_console_type == FNF) { + if (output_console_type == FNF) + { report_size = packet_size = sizeof(PCFortniteRockBandGuitar_Data_t); PCFortniteRockBandGuitar_Data_t *report = (PCFortniteRockBandGuitar_Data_t *)report_data; memset(report, 0, sizeof(PCFortniteRockBandGuitar_Data_t)); @@ -2703,15 +3638,50 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu asm volatile("" :: : "memory"); // alias tilt to dpad left so that tilt works - if (report->tilt > 200 || report->back) { + if (report->tilt > 200 || report->back) + { report->dpadLeft = true; } report->back = false; } + if (output_console_type == ARCADE) + { + report_size = packet_size = sizeof(ArcadeGuitarHeroGuitar_Data_t); + ArcadeGuitarHeroGuitar_Data_t *report = (ArcadeGuitarHeroGuitar_Data_t *)report_data; + memset(report, 0, sizeof(ArcadeGuitarHeroGuitar_Data_t)); + report->always_1d = 0x1d; + report->always_ff = 0xff; + report->tilt = 0; + report->side = arcadeSide; + TICK_ARCADE; + asm volatile("" :: + : "memory"); + if (report->dpadUp) + { + report->dpad = 0; + } + else if (report->dpadDown) + { + report->dpad = 2; + } + else if (report->dpadLeft) + { + report->dpad = 3; + } + else if (report->dpadRight) + { + report->dpad = 1; + } + else + { + report->dpad = 0xf; + } + } #endif // For gamepads, use the PS3 report format on PS3 #if DEVICE_TYPE == GAMEPAD - if (output_console_type == PS3) { + if (output_console_type == PS3) + { PS3Gamepad_Data_t *report = (PS3Gamepad_Data_t *)report_data; memset(report, 0, sizeof(PS3Gamepad_Data_t)); report->reportId = 1; @@ -2726,14 +3696,17 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu TICK_PS3_WITHOUT_CAPTURE; report_size = packet_size = sizeof(PS3Gamepad_Data_t); } - if (output_console_type != OG_XBOX && output_console_type != WINDOWS && output_console_type != XBOX360 && output_console_type != PS3 && output_console_type != BLUETOOTH_REPORT && output_console_type != UNIVERSAL && output_console_type != XBOXONE && output_console_type != PS4) { + if (output_console_type != OG_XBOX && output_console_type != WINDOWS && output_console_type != XBOX360 && output_console_type != PS3 && output_console_type != BLUETOOTH_REPORT && output_console_type != UNIVERSAL && output_console_type != XBOXONE && output_console_type != PS4 && output_console_type != PS5) + { #else // For instruments, we instead use the below block, as all other console types use the below format - if ((output_console_type != OG_XBOX && output_console_type != WINDOWS && output_console_type != KEYBOARD_MOUSE && output_console_type != IOS_FESTIVAL && output_console_type != FNF && output_console_type != XBOX360 && output_console_type != PS4 && output_console_type != BLUETOOTH_REPORT && output_console_type != UNIVERSAL && output_console_type != XBOXONE) || updateHIDSequence) { + if ((output_console_type != OG_XBOX && output_console_type != ARCADE && output_console_type != WINDOWS && output_console_type != KEYBOARD_MOUSE && output_console_type != IOS_FESTIVAL && output_console_type != FNF && output_console_type != XBOX360 && output_console_type != PS4 && output_console_type != PS5 && output_console_type != BLUETOOTH_REPORT && output_console_type != UNIVERSAL && output_console_type != XBOXONE) || updateHIDSequence) + { #endif report_size = sizeof(PS3_REPORT); // Do NOT update the size for XBONE, since the XBONE packets have a totally different size! - if (!updateHIDSequence) { + if (!updateHIDSequence) + { packet_size = report_size; } @@ -2754,8 +3727,39 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu gamepad->rightStickY = PS3_STICK_CENTER; #endif +#if DEVICE_TYPE_IS_GUITAR + + if (output_console_type == SWITCH) + { + SwitchFestivalGuitar_Data_t *report = (SwitchFestivalGuitar_Data_t *)report_data; + TICK_PS3; + asm volatile("" :: + : "memory"); + bool dpadLeft = report->dpadLeft; + bool back = report->back; + report->dpadLeft = false; + report->back = false; + report->whammy = 255 - report->whammy; + if (dpadLeft) + { + report->back = true; + } + if (back) + { + report->dpadLeft = true; + } + if (report->tilt < 0x190) + { + report->dpadLeft = true; + } + asm volatile("" :: + : "memory"); + gamepad->dpad = (gamepad->dpad & 0xf) > 0x0a ? 0x08 : dpad_bindings[gamepad->dpad]; + } +#endif #if DEVICE_TYPE == GUITAR_HERO_GUITAR - if (output_console_type == PS2_ON_PS3) { + else if (output_console_type == PS2_ON_PS3) + { PS2GuitarOnPS3_Data_t *report = (PS2GuitarOnPS3_Data_t *)report_data; TICK_PS3; @@ -2766,12 +3770,22 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu : "memory"); gamepad->dpad = (gamepad->dpad & 0xf) > 0x0a ? 0x08 : dpad_bindings[gamepad->dpad]; - } else { + } + else + { #endif #ifdef TICK_FESTIVAL - if (!festival_gameplay_mode) { + if (!festival_gameplay_mode) + { #endif PS3_REPORT *report = (PS3_REPORT *)report_data; +// rb drums have inverted velocity so they start at 0 +#if DEVICE_TYPE == ROCK_BAND_DRUMS + report->redVelocity = 0; + report->blueVelocity = 0; + report->greenVelocity = 0; + report->yellowVelocity = 0; +#endif #if DEVICE_TYPE == ROCK_BAND_GUITAR report->whammy = 0; #endif @@ -2783,10 +3797,78 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu #if PRO_GUITAR && BLUETOOTH_RX TRANSLATE_TO_PRO_GUITAR(bt_data) #endif + +#ifdef MUSTANG_NECK_SPI_PORT + report->lowEFret = lastProtar.lowEFret; + report->aFret = lastProtar.aFret; + report->dFret = lastProtar.dFret; + report->gFret = lastProtar.gFret; + report->bFret = lastProtar.bFret; + report->highEFret = lastProtar.highEFret; + report->green = lastProtar.green; + report->red = lastProtar.red; + report->yellow = lastProtar.yellow; + report->blue = lastProtar.blue; + report->orange = lastProtar.orange; + report->soloFlag = lastProtar.soloFlag; +#endif +#if DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_MUSTANG || DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_SQUIRE + if (midiData.seenProGuitar) + { + report->lowEFretVelocity = midiData.midiStringVelocities[5]; + report->aFretVelocity = midiData.midiStringVelocities[4]; + report->dFretVelocity = midiData.midiStringVelocities[3]; + report->gFretVelocity = midiData.midiStringVelocities[2]; + report->bFretVelocity = midiData.midiStringVelocities[1]; + report->highEFretVelocity = midiData.midiStringVelocities[0]; + report->tilt = midiData.proGuitarData.tilt ? 0x7F : 0x40; + report->start |= midiData.proGuitarData.start; + report->back |= midiData.proGuitarData.back; + report->guide |= midiData.proGuitarData.guide; +#if DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_SQUIRE + report->guide |= midiData.proGuitarData.start && midiData.proGuitarData.back; +#endif + report->a |= midiData.proGuitarData.a; + report->b |= midiData.proGuitarData.b; + report->x |= midiData.proGuitarData.x; + report->y |= midiData.proGuitarData.y; + + uint8_t dpad = midiData.proGuitarData.dpad; + dpad = dpad >= 0x08 ? 0 : dpad_bindings_reverse[dpad]; + asm volatile("" :: + : "memory"); + report->dpadUp |= (dpad & UP) != 0; + report->dpadLeft |= (dpad & LEFT) != 0; + report->dpadDown |= (dpad & DOWN) != 0; + report->dpadRight |= (dpad & RIGHT) != 0; + for (size_t i = 0; i < TU_ARRAY_SIZE(midiData.midiFrets); i++) + { + uint8_t fret = midiData.midiFrets[i]; + report->green |= fret == 1 || fret == 6 || fret == 13; + report->red |= fret == 2 || fret == 7 || fret == 14; + report->yellow |= fret == 3 || fret == 8 || fret == 15; + report->blue |= fret == 4 || fret == 9 || fret == 16; + report->orange |= fret == 5 || fret == 10 || fret == 17; + report->soloFlag |= fret >= 13 && fret <= 17; + } + report->lowEFret = midiData.midiFrets[5]; + report->aFret = midiData.midiFrets[4]; + report->dFret = midiData.midiFrets[3]; + report->gFret = midiData.midiFrets[2]; + report->bFret = midiData.midiFrets[1]; + report->highEFret = midiData.midiFrets[0]; + } +#endif + +#if PRO_GUITAR + report->autoCal_Light = report->tilt; + report->autoCal_Microphone = report->tilt; +#endif asm volatile("" :: : "memory"); #ifdef TICK_FESTIVAL - if (output_console_type == SWITCH) { + if (output_console_type == SWITCH) + { gamepad->accelX = PS3_ACCEL_CENTER; gamepad->accelY = PS3_ACCEL_CENTER; gamepad->accelZ = PS3_ACCEL_CENTER; @@ -2798,11 +3880,32 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu } #endif +#if DEVICE_TYPE == ROCK_BAND_DRUMS + if (!report->cymbalFlag && ready_for_next_packet() && (greenCymbal || yellowCymbal || blueCymbal)) + { + if (greenCymbal) + { + lastGreenOff = millis(); + } + greenCymbal = false; + yellowCymbal = false; + blueCymbal = false; + lastCymbalOff = millis(); + } + if (!report->padFlag && ready_for_next_packet() && greenPad) + { + greenPad = false; + lastGreenOff = millis(); + } +#endif + #if DEVICE_TYPE == ROCK_BAND_PRO_KEYS bool key25 = report->key25; uint8_t currentVel = 0; - for (int i = 0; i < sizeof(proKeyVelocities) && currentVel <= 4; i++) { - if (proKeyVelocities[i]) { + for (int i = 0; i < sizeof(proKeyVelocities) && currentVel <= 4; i++) + { + if (proKeyVelocities[i]) + { report->velocities[currentVel] = proKeyVelocities[i] >> 1; currentVel++; } @@ -2810,7 +3913,8 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu report->key25 = key25; #endif gamepad->dpad = (gamepad->dpad & 0xf) > 0x0a ? 0x08 : dpad_bindings[gamepad->dpad]; - if (SWAP_SWITCH_FACE_BUTTONS && output_console_type == SWITCH) { + if (SWAP_SWITCH_FACE_BUTTONS && output_console_type == SWITCH) + { bool a = gamepad->a; bool b = gamepad->b; bool x = gamepad->x; @@ -2821,9 +3925,16 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu gamepad->y = x; } #ifdef TICK_FESTIVAL - } else { + } + else + { +#if DEVICE_TYPE_IS_DRUM + SwitchFestivalProDrumsLayer_Data_t *report = (SwitchFestivalProDrumsLayer_Data_t *)report_data; + TICK_FESTIVAL; +#else SwitchFestivalProGuitarLayer_Data_t *report = (SwitchFestivalProGuitarLayer_Data_t *)report_data; TICK_FESTIVAL; +#endif asm volatile("" :: : "memory"); @@ -2837,45 +3948,51 @@ uint8_t tick_inputs(void *buf, USB_LastReport_Data_t *last_report, uint8_t outpu } TICK_RESET // Some hosts want packets sent every frame - if (last_report && output_console_type != OG_XBOX && output_console_type != PS4 && output_console_type != IOS_FESTIVAL && output_console_type != PS3 && output_console_type != BLUETOOTH_REPORT && output_console_type != XBOX360 && !updateHIDSequence) { + if (last_report && output_console_type != ARCADE && output_console_type != OG_XBOX && output_console_type != PS4 && output_console_type != PS5 && output_console_type != IOS_FESTIVAL && output_console_type != PS3 && output_console_type != BLUETOOTH_REPORT && !updateHIDSequence) + { uint8_t cmp = memcmp(last_report, report_data, report_size); - if (cmp == 0) { + if (cmp == 0) + { return 0; } memcpy(last_report, report_data, report_size); } // Standard PS4 controllers need a report counter, but we don't want to include that when comparing so we add it here #if SUPPORTS_PS4 - if (output_console_type == PS4) { + if (output_console_type == PS4) + { PS4Gamepad_Data_t *gamepad = (PS4Gamepad_Data_t *)report_data; gamepad->reportCounter = ps4_sequence_number++; } #endif -#if USB_HOST_STACK #if DEVICE_TYPE_IS_GAMEPAD - if (updateSequence) { + if (updateSequence) + { report_sequence_number++; - if (report_sequence_number == 0) { + if (report_sequence_number == 0) + { report_sequence_number = 1; } } #if DEVICE_TYPE_IS_LIVE_GUITAR - if (updateHIDSequence) { + if (updateHIDSequence) + { hid_sequence_number++; - if (hid_sequence_number == 0) { + if (hid_sequence_number == 0) + { hid_sequence_number = 1; } } #endif #endif -#endif #endif return packet_size; } #ifdef BLUETOOTH_TX -bool tick_bluetooth(void) { +bool tick_bluetooth(void) +{ uint8_t size = tick_inputs(&bt_report, &last_report_bt, BLUETOOTH_REPORT); send_report(size, (uint8_t *)&bt_report); return size; @@ -2885,103 +4002,164 @@ bool windows_in_hid = false; unsigned long millis_at_boot = 0; uint8_t init_packet_skylanders[32] = {0x0b, 0x14, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; uint8_t version_response_skylanders[32] = {0x0b, 0x14, 0x52, 0x02, 0x1B}; -bool tick_usb(void) { +bool tick_usb(void) +{ uint8_t size = 0; bool ready = ready_for_next_packet(); #ifdef BLUETOOTH_TX - if (!ready) { + if (!ready) + { return false; } #endif - if (millis_at_boot == 0 && read_device_desc) { + if (millis_at_boot == 0 && read_device_desc) + { millis_at_boot = millis(); } #if !DEVICE_TYPE_IS_KEYBOARD - if (!WINDOWS_USES_XINPUT) { + if (!WINDOWS_USES_XINPUT) + { // If we ended up here, then someone probably changed back to hid mode so we should jump back - if (consoleType == WINDOWS) { + if (consoleType == WINDOWS) + { consoleType = UNIVERSAL; reset_usb(); } } #endif #if DEVICE_TYPE_IS_GAMEPAD - // PS2 / Wii / WiiU do not read the hid report descriptor or any of the string descriptors. - if (millis_at_boot && (millis() - millis_at_boot) > 5000 && consoleType == UNIVERSAL && !seen_hid_descriptor_read && !read_any_string && !seen_windows_xb1) { + // PS2 / Wii / WiiU / Switch 2 won't do WCID and wont try to read any actual strings + if (millis_at_boot && (millis() - millis_at_boot) > 2000 && consoleType == UNIVERSAL && !seen_windows_xb1 && !seen_os_descriptor_read && !read_any_device_string) + { + // og xbox does its own thing + if (seen_og_xbox) + { + consoleType = OG_XBOX; + reset_usb(); + } + // Switch 2 does read the hid descriptor + if (seen_hid_descriptor_read) + { + consoleType = SWITCH; + reset_usb(); + } + // PS2 / Wii / WiiU does not read hid descriptor // The wii however will configure the usb device before it stops communicating #if DEVICE_TYPE == ROCK_BAND_GUITAR || DEVICE_TYPE == ROCK_BAND_DRUMS - if (usb_configured()) { + if (usb_configured()) + { set_console_type(WII_RB); } #endif // But the PS2 does not. We also end up here on the wii/wiiu if a device does not have an explicit wii mode. set_console_type(PS3); } - // Due to some quirks with how the PS3 detects controllers, we can also end up here for PS3, but in that case, we won't see any requests for controller data - if ((millis() - millis_at_boot) > 2000 && consoleType == PS4 && !seen_ps4) { - set_console_type(PS3); - } #endif - if (!ready) return 0; -#if USB_HOST_STACK - if (data_from_console_size) { - USB_Device_Type_t type = get_device_address_for(XBOXONE); - send_report_to_controller(type.dev_addr, type.instance, data_from_console, data_from_console_size); - data_from_console_size = 0; - } + if (!ready) + return 0; // If we have something pending to send to the xbox one controller, send it - if (consoleType == XBOXONE && xbox_one_state != Ready) { + if (consoleType == XBOXONE && xbox_one_state != Ready) + { size = tick_xbox_one(); - if (!size) { - // We don't want the controller ticked due to usb being stated as "not ready" - return true; - } - } -// #if DEVICE_TYPE == SKYLANDERS -// if (consoleType == XBOX360) { -// size = 32; -// switch (portal_state) { -// case 0: -// memcpy(&combined_report, init_packet_skylanders, sizeof(init_packet_skylanders)); -// break; -// case 1: -// memcpy(&combined_report, version_response_skylanders, sizeof(version_response_skylanders)); -// break; -// } -// } -// if (consoleType == XBOXONE) { -// size = 32; -// switch (portal_state) { -// case 0: -// memcpy(&combined_report, init_packet_skylanders, sizeof(init_packet_skylanders)); -// break; -// case 1: -// memcpy(&combined_report, version_response_skylanders, sizeof(version_response_skylanders)); -// break; -// } -// } -// #endif -#endif - if (!size) { + } + // #if DEVICE_TYPE == SKYLANDERS + // if (consoleType == XBOX360) { + // size = 32; + // switch (portal_state) { + // case 0: + // memcpy(&combined_report, init_packet_skylanders, sizeof(init_packet_skylanders)); + // break; + // case 1: + // memcpy(&combined_report, version_response_skylanders, sizeof(version_response_skylanders)); + // break; + // } + // } + // if (consoleType == XBOXONE) { + // size = 32; + // switch (portal_state) { + // case 0: + // memcpy(&combined_report, init_packet_skylanders, sizeof(init_packet_skylanders)); + // break; + // case 1: + // memcpy(&combined_report, version_response_skylanders, sizeof(version_response_skylanders)); + // break; + // } + // } + // #endif + if (!size) + { size = tick_inputs(&combined_report, &last_report_usb, consoleType); } - if (size) { - lastSentPacket = millis(); // make 5ms idle ticking wait until 5ms after last report + if (size) + { + lastSentPacket = millis(); // make 5ms idle ticking wait until 5ms after last report send_report_to_pc(&combined_report, size); } - seen_ps4_console = true; - return size; + report_requested = true; + return ready; +} +void onNote(uint8_t channel, uint8_t note, uint8_t velocity) +{ + // velocities are 7 bit + // printf("Note ON ch=%d, note=%d, vel=%d\r\n", channel, note, velocity); + velocity = velocity << 1; +#if DEVICE_TYPE_IS_DRUM + // drums, base inputs on triggers + if (velocity > midiData.midiVelocitiesTemp[note]) + { + midiData.midiVelocities[note] = velocity; + midiData.midiVelocitiesTemp[note] = velocity; + } +#else + // Handle midi normally + midiData.midiVelocities[note] = velocity; + midiData.midiVelocitiesTemp[note] = velocity; +#endif + lastMidi = millis(); +} + +void offNote(uint8_t channel, uint8_t note, uint8_t velocity) +{ + // printf("Note OFF ch=%d, note=%d, vel=%d\r\n", channel, note, velocity); + // ignore note off for drums as we handle that ourselves, and not all drums send it +#if !(DEVICE_TYPE_IS_DRUM) + midiData.midiVelocities[note] = 0; + midiData.midiVelocitiesTemp[note] = 0; +#endif +} + +void onControlChange(uint8_t channel, uint8_t b1, uint8_t b2) +{ + // cc are 7 bit + printf("ControlChange ch=%d, b1=%d, b2=%d\r\n", channel, b1, b2); + if (b1 == MIDI_CONTROL_COMMAND_SUSTAIN_PEDAL) + { + midiData.midiSustainPedal = b2 << 1; + } + if (b1 == MIDI_CONTROL_COMMAND_MOD_WHEEL) + { + midiData.midiModWheel = b2 << 1; + } +} + +void onPitchBend(uint8_t channel, int pitch) +{ + // pitchbend is signed 14 bit + printf("PitchBend ch=%d, pitch=%d\r\n", channel, pitch); + midiData.midiPitchWheel = pitch << 2; } #if BLUETOOTH_RX -int tick_bluetooth_inputs(const void *data, uint8_t len, USB_Device_Type_t device_type) { +int tick_bluetooth_inputs(const void *data, uint8_t len, USB_Device_Type_t device_type) +{ memset(&bt_data, 0, sizeof(bt_data)); bt_data.slider = 0x80; convert_report((const uint8_t *)data, len, device_type, &bt_data); return 0; } #endif -void tick(void) { +void tick(void) +{ #ifdef SLAVE_TWI_PORT tick_slave(); #endif @@ -2994,50 +4172,73 @@ void tick(void) { #ifdef TICK_LED_BLUETOOTH TICK_LED_BLUETOOTH; #endif + + usbMidi.update(false, false); + serialMidi.update(false, false); + + if (reset_after_360 && millis() > reset_after_360) + { + reset_usb(); + } // Only sleep if the timeout has passed and we aren't connected over USB - if (SLEEP_PIN != -1 && SLEEP_INACTIVITY_TIMEOUT_MS && millis() - lastInputActivity >= SLEEP_INACTIVITY_TIMEOUT_MS && !usb_configured()) { + if (SLEEP_PIN != -1 && SLEEP_INACTIVITY_TIMEOUT_SEC && millis() - lastInputActivity >= ((uint32_t)SLEEP_INACTIVITY_TIMEOUT_SEC * 1000) && !usb_configured()) + { go_to_sleep(); } - // Tick inputs constantly for detection - if ((millis() - input_start) < 2000) { + // Tick inputs constantly for detection for 2 seconds + // Tick inputs constantly for xbox 360 wakeup if usb isnt configured + if ((millis() - input_start) < 2000 || !usb_configured()) + { tick_inputs(NULL, NULL, consoleType); } - if ((millis() - lastMidi) > 1000) { +#if DEVICE_TYPE != ROCK_BAND_PRO_KEYS + if ((millis() - lastMidi) > 1000) + { memset(midiData.midiVelocities, 0, sizeof(midiData.midiVelocities)); lastMidi = millis(); } +#endif #ifdef TICK_LED_PERIPHERAL // If we are controlling peripheral leds, then we need to send the latest state when // the device is plugged in again - if (slave_initted) { - if (RGB_INACTIVITY_TIMEOUT_MS && millis() - lastInputActivity >= RGB_INACTIVITY_TIMEOUT_MS) { + if (slave_initted) + { + if (RGB_INACTIVITY_TIMEOUT_SEC && millis() - lastInputActivity >= (((uint32_t)RGB_INACTIVITY_TIMEOUT_SEC) * 1000)) + { memset(ledStatePeripheral, 0, sizeof(ledStatePeripheral)); } - if (memcmp(lastLedStatePeripheral, ledStatePeripheral, sizeof(ledStatePeripheral)) != 0) { + if (memcmp(lastLedStatePeripheral, ledStatePeripheral, sizeof(ledStatePeripheral)) != 0) + { memcpy(lastLedStatePeripheral, ledStatePeripheral, sizeof(ledStatePeripheral)); TICK_LED_PERIPHERAL; } - } else { + } + else + { memset(lastLedStatePeripheral, 0, sizeof(lastLedStatePeripheral)); } #endif #ifdef TICK_LED - if (RGB_INACTIVITY_TIMEOUT_MS && millis() - lastInputActivity >= RGB_INACTIVITY_TIMEOUT_MS) { + if (RGB_INACTIVITY_TIMEOUT_SEC && millis() - lastInputActivity >= (((uint32_t)RGB_INACTIVITY_TIMEOUT_SEC) * 1000)) + { memset(ledState, 0, sizeof(ledState)); } - if (memcmp(lastLedState, ledState, sizeof(ledState)) != 0) { + if (memcmp(lastLedState, ledState, sizeof(ledState)) != 0) + { memcpy(lastLedState, ledState, sizeof(ledState)); TICK_LED; } #endif #if LED_COUNT_MPR121 - if (RGB_INACTIVITY_TIMEOUT_MS && millis() - lastInputActivity >= RGB_INACTIVITY_TIMEOUT_MS) { + if (RGB_INACTIVITY_TIMEOUT_SEC && millis() - lastInputActivity >= (((uint32_t)RGB_INACTIVITY_TIMEOUT_SEC) * 1000)) + { ledStateMpr121 = 0; } - if (lastLedStateMpr121 != ledStateMpr121) { + if (lastLedStateMpr121 != ledStateMpr121) + { lastLedStateMpr121 = ledStateMpr121; twi_writeSingleToPointer(MPR121_TWI_PORT, MPR121_I2CADDR_DEFAULT, MPR121_GPIODATA, ledStateMpr121); } @@ -3045,38 +4246,48 @@ void tick(void) { #ifdef TICK_PS2 tick_ps2output(); #endif - if (!INPUT_QUEUE && micros() - lastDebounce > 1000) { + if (!INPUT_QUEUE && micros() - lastDebounce > 1000) + { // No benefit to ticking bluetooth faster than this! #ifdef BLUETOOTH_TX tick_bluetooth(); #endif lastDebounce = micros(); - for (int i = 0; i < DIGITAL_COUNT; i++) { - if (debounce[i]) { + for (int i = 0; i < DIGITAL_COUNT; i++) + { + if (debounce[i]) + { debounce[i]--; } } #if REQUIRE_LED_DEBOUNCE - for (int i = 0; i < LED_DEBOUNCE_COUNT; i++) { - if (ledDebounce[i]) { + for (int i = 0; i < LED_DEBOUNCE_COUNT; i++) + { + if (ledDebounce[i]) + { ledDebounce[i]--; } } #endif } #if DEVICE_TYPE_IS_GUITAR - if (consoleType == KEYBOARD_MOUSE || consoleType == FNF) { - if (!INPUT_QUEUE && (micros() - last_poll) < (4000)) { + if (consoleType == KEYBOARD_MOUSE || consoleType == FNF) + { + if (!INPUT_QUEUE && (micros() - last_poll) < (4000)) + { return; } } #endif - if (!INPUT_QUEUE && POLL_RATE && (micros() - last_poll) < (POLL_RATE * 1000)) { + if (!INPUT_QUEUE && POLL_RATE && (micros() - last_poll) < (POLL_RATE * 1000)) + { return; } #if DEVICE_TYPE == DJ_HERO_TURNTABLE - if (consoleType == PS3) { - if (!INPUT_QUEUE && (micros() - last_poll_dj_ps3) < (10000)) { + if (consoleType == PS3) + { + if (!INPUT_QUEUE && (micros() - last_poll_dj_ps3) < (10000)) + { tick_inputs(NULL, NULL, consoleType); return; } @@ -3089,48 +4300,57 @@ void tick(void) { bool ready = tick_usb(); // Input queuing is enabled, tick as often as possible - if (INPUT_QUEUE && !ready) { + if (INPUT_QUEUE && !ready) + { tick_inputs(NULL, NULL, consoleType); } last_poll = micros(); - // Tick the controller every 5ms if this device is connected to a usb port and usb is not ready - if (!INPUT_QUEUE && !ready && usb_configured() && millis() - lastSentPacket >= 5) { + // Tick the controller every 1ms if this device is connected to a usb port and usb is not ready + if (!INPUT_QUEUE && !ready && usb_configured() && millis() - lastSentPacket >= 1) + { lastSentPacket = millis(); tick_inputs(NULL, NULL, consoleType); } #if HEARTBEAT_PERIOD_MS - if ((lastHeartbeat == 0) || (millis() - lastHeartbeat >= HEARTBEAT_PERIOD_MS)) { + if ((lastHeartbeat == 0) || (millis() - lastHeartbeat >= HEARTBEAT_PERIOD_MS)) + { // heartbeat resets regularly regardless of activity lastHeartbeat = millis(); // trigger output only if inputs have been active though - if (millis() - lastInputActivity < HEARTBEAT_INACTIVITY_TIMEOUT_MS) { + if (millis() - lastInputActivity < HEARTBEAT_INACTIVITY_TIMEOUT_MS) + { uint8_t activeMask = HEARTBEAT_INVERT ? 0 : HEARTBEAT_GPIO_MASK; digital_write(HEARTBEAT_GPIO_PORT, HEARTBEAT_GPIO_MASK, activeMask); } } // unset heartbeat output if pulse is over - if (millis() - lastHeartbeat >= HEARTBEAT_PULSE_DURATION_MS) { + if (millis() - lastHeartbeat >= HEARTBEAT_PULSE_DURATION_MS) + { uint8_t activeMask = HEARTBEAT_INVERT ? HEARTBEAT_GPIO_MASK : 0; digital_write(HEARTBEAT_GPIO_PORT, HEARTBEAT_GPIO_MASK, activeMask); } -#endif // HEARTBEAT_PERIOD_MS +#endif // HEARTBEAT_PERIOD_MS #if INACTIVITY_OUTPUT_TIMEOUT_MS #if INACTIVITY_OUTPUT_NON_USB_ONLY - if (!usb_configured()) { -#endif // INACTIVITY_OUTPUT_NON_USB_ONLY - // unlike heartbeat, no regular resetting cycle - just a timeout for the - // inactivity output - if (millis() - lastInputActivity >= INACTIVITY_OUTPUT_TIMEOUT_MS) { + if (!usb_configured()) + { +#endif // INACTIVITY_OUTPUT_NON_USB_ONLY + // unlike heartbeat, no regular resetting cycle - just a timeout for the + // inactivity output + if (millis() - lastInputActivity >= INACTIVITY_OUTPUT_TIMEOUT_MS) + { #if INACTIVITY_OUTPUT_PULSE_COUNT // gate to check if already done outputting pulses // (technically not super ideal because lastInactivityPulse may slightly desynchronise, // but should be fine for intended purpose of a few fairly long pulses) - if (millis() - lastInputActivity - INACTIVITY_OUTPUT_TIMEOUT_MS < INACTIVITY_OUTPUT_PULSE_TOTAL_MS) { + if (millis() - lastInputActivity - INACTIVITY_OUTPUT_TIMEOUT_MS < INACTIVITY_OUTPUT_PULSE_TOTAL_MS) + { startedInactivityPulse = true; - if (millis() - lastInactivityPulse >= INACTIVITY_OUTPUT_PULSE_PERIOD_MS) { + if (millis() - lastInactivityPulse >= INACTIVITY_OUTPUT_PULSE_PERIOD_MS) + { lastInactivityPulse = millis(); // input activity has already been checked, so no need to recheck // - just set the output @@ -3138,22 +4358,27 @@ void tick(void) { digital_write(INACTIVITY_OUTPUT_GPIO_PORT, INACTIVITY_OUTPUT_GPIO_MASK, activeMask); } // unset output once current pulse's duration is over - if (millis() - lastInactivityPulse >= INACTIVITY_OUTPUT_PULSE_DURATION_MS) { + if (millis() - lastInactivityPulse >= INACTIVITY_OUTPUT_PULSE_DURATION_MS) + { uint8_t activeMask = INACTIVITY_OUTPUT_INVERT ? INACTIVITY_OUTPUT_GPIO_MASK : 0; digital_write(INACTIVITY_OUTPUT_GPIO_PORT, INACTIVITY_OUTPUT_GPIO_MASK, activeMask); } - } else { + } + else + { startedInactivityPulse = false; // unset output once all pulses are done uint8_t activeMask = INACTIVITY_OUTPUT_INVERT ? INACTIVITY_OUTPUT_GPIO_MASK : 0; digital_write(INACTIVITY_OUTPUT_GPIO_PORT, INACTIVITY_OUTPUT_GPIO_MASK, activeMask); } -#else // INACTIVITY_OUTPUT_PULSE_COUNT - // set output continuously on if no pulses +#else // INACTIVITY_OUTPUT_PULSE_COUNT + // set output continuously on if no pulses uint8_t activeMask = INACTIVITY_OUTPUT_INVERT ? 0 : INACTIVITY_OUTPUT_GPIO_MASK; digital_write(INACTIVITY_OUTPUT_GPIO_PORT, INACTIVITY_OUTPUT_GPIO_MASK, activeMask); -#endif // INACTIVITY_OUTPUT_PULSE_COUNT - } else { +#endif // INACTIVITY_OUTPUT_PULSE_COUNT + } + else + { startedInactivityPulse = false; // unset output when inputs have been active uint8_t activeMask = INACTIVITY_OUTPUT_INVERT ? INACTIVITY_OUTPUT_GPIO_MASK : 0; @@ -3161,14 +4386,17 @@ void tick(void) { } #if INACTIVITY_OUTPUT_NON_USB_ONLY } -#endif // INACTIVITY_OUTPUT_NON_USB_ONLY -#endif // INACTIVITY_OUTPUT_TIMEOUT_MS +#endif // INACTIVITY_OUTPUT_NON_USB_ONLY +#endif // INACTIVITY_OUTPUT_TIMEOUT_MS } -void device_reset(void) { +void device_reset(void) +{ #if USB_HOST_STACK - if (consoleType == XBOXONE) { - if (xbox_one_state != Announce && xbox_one_state != WaitingDesc1) { + if (consoleType == XBOXONE) + { + if (xbox_one_state != Announce && xbox_one_state != WaitingDesc1) + { powerMode.subcommand = 0x07; USB_Device_Type_t type = get_device_address_for(XBOXONE); send_report_to_controller(type.dev_addr, type.instance, (uint8_t *)&powerMode, sizeof(GipPowerMode_t)); @@ -3177,73 +4405,60 @@ void device_reset(void) { } #endif xbox_one_state = Announce; - data_from_controller_size = 0; - data_from_console_size = 0; hid_sequence_number = 1; report_sequence_number = 1; } uint8_t last_len = 0; -void receive_report_from_controller(uint8_t const *report, uint16_t len) { - if (report[0] == GIP_INPUT_REPORT) { +#include +void receive_report_from_controller(uint8_t const *report, uint16_t len) +{ + if (report[0] == GIP_INPUT_REPORT) + { report_sequence_number = report[2] + 1; } const GipHeader_t *header = (const GipHeader_t *)report; - if (header->command == GIP_ARRIVAL) { + if (header->command == GIP_ARRIVAL) + { return; } - if (xbox_one_state != Auth) { + if (xbox_one_state != Auth) + { return; } - data_from_controller_size = len; - memcpy(data_from_controller, report, len); + while (!ready_for_next_packet()) + { + tud_task(); + } + send_report_to_pc(report, len); } -void xinput_controller_connected(uint16_t vid, uint16_t pid) { +void xinput_controller_connected(uint16_t vid, uint16_t pid) +{ handle_player_leds(0); - if (xbox_360_state == Authenticated) return; - xbox_360_vid = vid; - xbox_360_pid = pid; - // Using the skylander pid on a 360 results in it not being classed as a controller - // IDs from the xplorer auth just fine with the portals blobs however - if (xbox_360_vid == XBOX_REDOCTANE_VID && xbox_360_pid == 0x1f17) { - xbox_360_pid = 0x4748; - } - // Same thing with disney infinity portals and lego dimensions portals - if (xbox_360_vid == XBOX_POWERA_VID && (xbox_360_pid == 0xFA00 || xbox_360_pid == 0xFA01)) { - xbox_360_pid = 0x4748; - } - // Skylanders games require you use the portal vid and pid -#if DEVICE_TYPE == SKYLANDERS - if (xbox_360_vid == XBOX_REDOCTANE_VID) { - xbox_360_pid = 0x1f17; - } -#endif -#if DEVICE_TYPE == DISNEY_INFINITY - if (xbox_360_vid == XBOX_POWERA_VID) { - xbox_360_pid = 0xFA00; - } -#endif -#if DEVICE_TYPE == LEGO_DIMENSIONS - if (xbox_360_vid == XBOX_POWERA_VID) { - xbox_360_pid = 0xFA01; - } -#endif + if (xbox_360_state == Authenticated) + return; } -void xinput_w_controller_connected() { +void xinput_w_controller_connected() +{ handle_player_leds(0); } -void xone_controller_connected(uint8_t dev_addr, uint8_t instance) { +void xone_controller_connected(uint8_t dev_addr, uint8_t instance) +{ printf("Sending to controller %d\r\n", dev_addr); send_report_to_controller(dev_addr, instance, (uint8_t *)&powerMode, sizeof(GipPowerMode_t)); } -bool xone_controller_send_init_packet(uint8_t dev_addr, uint8_t instance, uint8_t id) { - if (id == 0) { +bool xone_controller_send_init_packet(uint8_t dev_addr, uint8_t instance, uint8_t id) +{ + if (id == 0) + { send_report_to_controller(dev_addr, instance, (uint8_t *)&ledOn, sizeof(ledOn)); return true; - } else if (id == 1 && consoleType != XBOXONE) { + } + else if (id == 1 && consoleType != XBOXONE) + { // When used for auth, the console will send this send_report_to_controller(dev_addr, instance, (uint8_t *)&authDonePacket, sizeof(authDonePacket)); return true; @@ -3251,293 +4466,391 @@ bool xone_controller_send_init_packet(uint8_t dev_addr, uint8_t instance, uint8_ return false; } -void host_controller_connected() { +void host_controller_connected() +{ // With input_usb_host, we need to run detection for a little bit after the input is detected #ifdef INPUT_USB_HOST input_start = millis(); #endif } -void ps4_controller_connected(uint8_t dev_addr, uint16_t vid, uint16_t pid) { - if (vid == SONY_VID && (pid == PS4_DS_PID_1 || pid == PS4_DS_PID_2 || pid == PS4_DS_PID_3)) { +void ps4_controller_connected(uint8_t dev_addr, uint16_t vid, uint16_t pid) +{ + if (vid == SONY_VID && (pid == PS4_DS_PID_1 || pid == PS4_DS_PID_2 || pid == PS4_DS_PID_3)) + { handle_player_leds(0); } auth_ps4_controller_found = true; } -void ps3_controller_connected(uint8_t dev_addr, uint16_t vid, uint16_t pid) { - if (vid == SONY_VID && pid == SONY_DS3_PID) { - // Enable PS3 reports - uint8_t hid_command_enable[] = {0x42, 0x0c, 0x00, 0x00}; - transfer_with_usb_controller(dev_addr, (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_SET_REPORT, 0x03F4, 0x00, sizeof(hid_command_enable), hid_command_enable, NULL); - handle_player_leds(0); - } +void ps3_controller_connected(uint8_t dev_addr, uint16_t vid, uint16_t pid) +{ } -void ps4_controller_disconnected(void) { +void ps4_controller_disconnected(void) +{ auth_ps4_controller_found = false; } -void set_console_type(uint8_t new_console_type) { - if (consoleType == new_console_type && new_console_type != UNIVERSAL) return; +void set_console_type(uint8_t new_console_type) +{ + if (consoleType == new_console_type && new_console_type != UNIVERSAL) + return; consoleType = new_console_type; reset_usb(); } #if USB_HOST_STACK || BLUETOOTH_RX -void get_usb_device_type_for(uint16_t vid, uint16_t pid, uint16_t version, USB_Device_Type_t *type) { - switch (vid) { - case STREAM_DECK_VID: { - type->console_type = STREAM_DECK; - type->sub_type = UNKNOWN; - switch (pid) { - case STREAM_DECK_OG_PID: - type->sub_type = STREAM_DECK_OG; - break; - case STREAM_DECK_MINI_PID: - type->sub_type = STREAM_DECK_MINI; - break; - case STREAM_DECK_XL_PID: - type->sub_type = STREAM_DECK_XL; - break; - case STREAM_DECK_V2_PID: - type->sub_type = STREAM_DECK_V2; - break; - case STREAM_DECK_MK2_PID: - type->sub_type = STREAM_DECK_MK2; - break; - case STREAM_DECK_PLUS_PID: - type->sub_type = STREAM_DECK_PLUS; - break; - case STREAM_DECK_PEDAL_PID: - type->sub_type = STREAM_DECK_PEDAL; - break; - case STREAM_DECK_XLV2_PID: - type->sub_type = STREAM_DECK_XLV2; - break; - case STREAM_DECK_MINIV2_PID: - type->sub_type = STREAM_DECK_MINIV2; - break; - case STREAM_DECK_NEO_PID: - type->sub_type = STREAM_DECK_NEO; - break; - } - break; - } - case NINTENDO_VID: { - if (pid == SWITCH_PRO_PID) { - type->console_type = SWITCH; - type->sub_type = GAMEPAD; - } - break; - } - case ARDWIINO_VID: { - if (pid == ARDWIINO_PID) { - type->console_type = SANTROLLER; - type->sub_type = (version >> 8) & 0xFF; - } - break; - } - case RAPHNET_VID: { - type->console_type = RAPHNET; +void get_usb_device_type_for(uint16_t vid, uint16_t pid, uint16_t version, USB_Device_Type_t *type) +{ + switch (vid) + { + case STREAM_DECK_VID: + { + type->console_type = STREAM_DECK; + type->sub_type = UNKNOWN; + switch (pid) + { + case STREAM_DECK_OG_PID: + type->sub_type = STREAM_DECK_OG; + break; + case STREAM_DECK_MINI_PID: + type->sub_type = STREAM_DECK_MINI; + break; + case STREAM_DECK_XL_PID: + type->sub_type = STREAM_DECK_XL; + break; + case STREAM_DECK_V2_PID: + type->sub_type = STREAM_DECK_V2; + break; + case STREAM_DECK_MK2_PID: + type->sub_type = STREAM_DECK_MK2; + break; + case STREAM_DECK_PLUS_PID: + type->sub_type = STREAM_DECK_PLUS; + break; + case STREAM_DECK_PEDAL_PID: + type->sub_type = STREAM_DECK_PEDAL; + break; + case STREAM_DECK_XLV2_PID: + type->sub_type = STREAM_DECK_XLV2; + break; + case STREAM_DECK_MINIV2_PID: + type->sub_type = STREAM_DECK_MINIV2; + break; + case STREAM_DECK_NEO_PID: + type->sub_type = STREAM_DECK_NEO; + break; + } + break; + } + case NINTENDO_VID: + { + if (pid == SWITCH_PRO_PID) + { + type->console_type = SWITCH; + } + if (pid == SWITCH_2_PRO_PID) + { + type->console_type = SWITCH2; + } + if (pid == SWITCH_2_GC_PID) + { + type->console_type = SWITCH2; + } + if (pid == SWITCH_2_JOY_R_PID) + { + type->console_type = SWITCH2; + } + if (pid == SWITCH_2_JOY_L_PID) + { + type->console_type = SWITCH2; + } + break; + } + case ARDWIINO_VID: + { + if (pid == ARDWIINO_PID) + { + type->console_type = SANTROLLER; + type->sub_type = (version >> 8) & 0xFF; + } + break; + } + case RAPHNET_VID: + { + type->console_type = RAPHNET; + type->sub_type = GAMEPAD; + break; + } + case MAGICBOOTS_PS4_VID: + { + if (pid == MAGICBOOTS_PS4_PID) + { + type->console_type = PS4; + type->sub_type = GAMEPAD; + } + break; + } + case ARDUINO_VID: + { + if (pid == STEPMANIA_X_PID) + { + type->console_type = STEPMANIAX; + type->sub_type = DANCE_PAD; + } + break; + } + case LTEK_LUFA_VID: + { + if (pid == LTEK_LUFA_PID) + { + type->console_type = LTEK_ID; + type->sub_type = DANCE_PAD; + } + break; + } + case LTEK_VID: + { + if (pid == LTEK_PID) + { + type->console_type = LTEK; + type->sub_type = DANCE_PAD; + } + break; + } + case SONY_VID: + switch (pid) + { + case SONY_DS3_PID: + type->console_type = PS3; + type->sub_type = GAMEPAD; + break; + case PS4_DS_PID_1: + case PS4_DS_PID_2: + case PS4_DS_PID_3: + type->console_type = PS4; + type->sub_type = GAMEPAD; + break; + case PS5_DS_PID: + case PS5_DS_EDGE_PID: + type->console_type = PS5; type->sub_type = GAMEPAD; break; } - case MAGICBOOTS_PS4_VID: { - if (pid == MAGICBOOTS_PS4_PID) { - type->console_type = PS4; - type->sub_type = GAMEPAD; - } - break; - } - case ARDUINO_VID: { - if (pid == STEPMANIA_X_PID) { - type->console_type = STEPMANIAX; - type->sub_type = DANCE_PAD; - } - break; - } - case LTEK_LUFA_VID: { - if (pid == LTEK_LUFA_PID) { - type->console_type = LTEK_ID; - type->sub_type = DANCE_PAD; - } - break; - } - case LTEK_VID: { - if (pid == LTEK_PID) { - type->console_type = LTEK; - type->sub_type = DANCE_PAD; - } - break; - } - case SONY_VID: - switch (pid) { - case SONY_DS3_PID: - type->console_type = PS3; - type->sub_type = GAMEPAD; - break; - case PS4_DS_PID_1: - case PS4_DS_PID_2: - case PS4_DS_PID_3: - type->console_type = PS4; - type->sub_type = GAMEPAD; - break; - case PS5_DS_PID: - type->console_type = PS5; - type->sub_type = GAMEPAD; - break; - } - break; - case STADIA_VID: - if (pid == STADIA_PID) { - type->console_type = STADIA; - type->sub_type = GAMEPAD; - } - break; - case REDOCTANE_VID: - switch (pid) { - case PS3_GH_GUITAR_PID: - type->console_type = PS3; - type->sub_type = GUITAR_HERO_GUITAR; - break; - case PS3_GH_DRUM_PID: - type->console_type = PS3; - type->sub_type = GUITAR_HERO_DRUMS; - break; - case PS3_RB_GUITAR_PID: - type->console_type = PS3; - type->sub_type = ROCK_BAND_GUITAR; - break; - case PS3_RB_DRUM_PID: - type->console_type = PS3; - type->sub_type = ROCK_BAND_DRUMS; - break; - case PS3_DJ_TURNTABLE_PID: - type->console_type = PS3; - type->sub_type = DJ_HERO_TURNTABLE; - break; - case PS3WIIU_GHLIVE_DONGLE_PID: - type->console_type = PS3; - type->sub_type = LIVE_GUITAR; - break; - case PS3_MPA_KEYBOARD_PID: - case PS3_KEYBOARD_PID: - type->console_type = PS3; - type->sub_type = ROCK_BAND_PRO_KEYS; - break; - case PS3_MUSTANG_PID: - case PS3_MUSTANG_MPA_PID: - type->console_type = PS3; - type->sub_type = ROCK_BAND_PRO_GUITAR_MUSTANG; - break; - case PS3_SQUIRE_PID: - case PS3_SQUIRE_MPA_PID: - type->console_type = PS3; - type->sub_type = ROCK_BAND_PRO_GUITAR_SQUIRE; - break; - } - break; - case HORI_VID: - switch (pid) { - case HORI_SWITCH_TAIKO_PID: - type->console_type = SWITCH; - type->sub_type = TAIKO; - break; - } - - case HARMONIX_VID: - // Polled the same as PS3, so treat them as PS3 instruments - switch (pid) { - case WII_RB_GUITAR_PID: - case WII_RB_GUITAR_2_PID: - type->console_type = PS3; - type->sub_type = ROCK_BAND_GUITAR; - break; - - case WII_RB_DRUM_PID: - case WII_RB_DRUM_2_PID: - type->console_type = PS3; - type->sub_type = ROCK_BAND_DRUMS; - break; - case WII_KEYBOARD_PID: - case WII_MPA_KEYBOARD_PID: - type->console_type = PS3; - type->sub_type = ROCK_BAND_PRO_KEYS; - break; - case WII_MUSTANG_PID: - case WII_MUSTANG_MPA_PID: - type->console_type = PS3; - type->sub_type = ROCK_BAND_PRO_GUITAR_MUSTANG; - break; - case WII_SQUIRE_PID: - case WII_SQUIRE_MPA_PID: - type->console_type = PS3; - type->sub_type = ROCK_BAND_PRO_GUITAR_SQUIRE; - break; - } - - break; - case PDP_VID: - switch (pid) { - case XBOX_ONE_JAG_PID: - case XBOX_ONE_RIFFMASTER_PID: - type->console_type = XBOXONE; - type->sub_type = ROCK_BAND_GUITAR; - break; - case PS4_JAG_PID: - case PS4_RIFFMASTER_PID: - type->console_type = PS4; - type->sub_type = ROCK_BAND_GUITAR; - break; - case PS5_RIFFMASTER_PID: - type->console_type = PS5; - type->sub_type = ROCK_BAND_GUITAR; - break; - } - - break; - - case MAD_CATZ_VID: - switch (pid) { - case XBOX_ONE_RB_GUITAR_PID: - type->console_type = XBOXONE; - type->sub_type = ROCK_BAND_GUITAR; - break; - case XBOX_ONE_RB_DRUM_PID: - type->console_type = XBOXONE; - type->sub_type = ROCK_BAND_DRUMS; - break; - case PS4_STRAT_PID: - type->console_type = PS4; - type->sub_type = ROCK_BAND_GUITAR; - break; - } - - break; - - case XBOX_REDOCTANE_VID: - switch (pid) { - case XBOX_ONE_GHLIVE_DONGLE_PID: - type->console_type = XBOXONE; - type->sub_type = LIVE_GUITAR; - break; - case XBOX_360_GHLIVE_DONGLE_PID: - type->console_type = XBOX360; - type->sub_type = XINPUT_GUITAR_HERO_LIVE; - break; - case XBOX_360_WT_KIOSK_PID: - type->console_type = XBOX360; - type->sub_type = XINPUT_GUITAR_WT; - break; - } - break; - case XBOX_ONE_CONTROLLER_VID: - if (pid >= 0x02e0 && pid <= 0x02eF) { - type->console_type = XINPUTCOMPAT; - type->sub_type = GAMEPAD; - break; + break; + case STADIA_VID: + if (pid == STADIA_PID) + { + type->console_type = STADIA; + type->sub_type = GAMEPAD; + } + break; + case REDOCTANE_VID: + switch (pid) + { + case PS3_GH_GUITAR_PID: + type->console_type = PS3; + type->sub_type = GUITAR_HERO_GUITAR; + break; + case PS3_GH_DRUM_PID: + type->console_type = PS3; + type->sub_type = GUITAR_HERO_DRUMS; + type->drum_type = DRUM_GH; + break; + case PS3_RB_GUITAR_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_GUITAR; + break; + case PS3_MPA_DRUM_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_DRUMS; + type->drum_type = DRUM_RB2; + break; + case PS3_RB_DRUM_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_DRUMS; + type->drum_type = version == 0x1000 ? DRUM_RB1 : DRUM_RB2; + break; + case PS3_DJ_TURNTABLE_PID: + type->console_type = PS3; + type->sub_type = DJ_HERO_TURNTABLE; + break; + case PS3WIIU_GHLIVE_DONGLE_PID: + type->console_type = PS3; + type->sub_type = LIVE_GUITAR; + break; + case PS3_MPA_KEYBOARD_PID: + case PS3_KEYBOARD_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_PRO_KEYS; + break; + case PS3_MUSTANG_PID: + case PS3_MUSTANG_MPA_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_PRO_GUITAR_MUSTANG; + if (DEVICE_TYPE_IS_PRO_GUITAR && proGuitarType != type->sub_type) + { + proGuitarType = type->sub_type; + reset_usb(); + } + break; + case PS3_SQUIRE_MPA_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_PRO_GUITAR_SQUIRE; + if (DEVICE_TYPE_IS_PRO_GUITAR && proGuitarType != type->sub_type) + { + proGuitarType = type->sub_type; + reset_usb(); } break; + } + break; + case HORI_VID: + switch (pid) + { + case HORI_SWITCH_TAIKO_PID: + type->console_type = SWITCH; + type->sub_type = TAIKO; + break; + } + + case HARMONIX_VID: + // Polled the same as PS3, so treat them as PS3 instruments + switch (pid) + { + case WII_RB_GUITAR_PID: + case WII_RB_GUITAR_2_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_GUITAR; + break; + + case WII_RB_DRUM_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_DRUMS; + type->drum_type = DRUM_RB1; + break; + case WII_RB_DRUM_2_PID: + case WII_MPA_DRUMS_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_DRUMS; + type->drum_type = DRUM_RB2; + break; + case WII_KEYBOARD_PID: + case WII_MPA_KEYBOARD_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_PRO_KEYS; + break; + case WII_MUSTANG_PID: + case WII_MUSTANG_MPA_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_PRO_GUITAR_MUSTANG; + break; + case WII_SQUIRE_MPA_PID: + type->console_type = PS3; + type->sub_type = ROCK_BAND_PRO_GUITAR_SQUIRE; + break; + case XBOX_360_ION_ROCKER_VID: + type->drum_type = DRUM_ION; + break; + } + + break; + case REDOCTANE_GAMES_VID: + switch (pid) + { + case CRKD_XB_MODE9: + type->console_type = XBOXONE; + type->sub_type = ROCK_BAND_GUITAR; + break; + case 0xD300: + type->console_type = XBOXONE; + type->sub_type = ROCK_BAND_DRUMS; + type->drum_type = DRUM_RB2; + break; + } + break; + case CRKD_VID: + switch (pid) + { + case 0x2200: + case 0x8200: + case 0x8210: + case CRKD_XB_MODE9: + type->console_type = XBOXONE; + type->sub_type = ROCK_BAND_GUITAR; + break; + } + break; + case PDP_VID: + switch (pid) + { + case XBOX_ONE_JAG_PID: + case XBOX_ONE_RIFFMASTER_PID: + type->console_type = XBOXONE; + type->sub_type = ROCK_BAND_GUITAR; + break; + case PS4_JAG_PID: + case PS4_RIFFMASTER_PID: + type->console_type = PS4; + type->sub_type = ROCK_BAND_GUITAR; + break; + case PS5_RIFFMASTER_PID: + type->console_type = PS5; + type->sub_type = ROCK_BAND_GUITAR; + break; + } + + break; + + case MAD_CATZ_VID: + switch (pid) + { + case XBOX_ONE_RB_GUITAR_PID: + type->console_type = XBOXONE; + type->sub_type = ROCK_BAND_GUITAR; + break; + case XBOX_ONE_RB_DRUM_PID: + type->console_type = XBOXONE; + type->sub_type = ROCK_BAND_DRUMS; + type->drum_type = DRUM_RB2; + break; + case PS4_STRAT_PID: + type->console_type = PS4; + type->sub_type = ROCK_BAND_GUITAR; + break; + } + + break; + + case XBOX_REDOCTANE_VID: + switch (pid) + { + case XBOX_ONE_GHLIVE_DONGLE_PID: + type->console_type = XBOXONE; + type->sub_type = LIVE_GUITAR; + break; + case XBOX_360_GHLIVE_DONGLE_PID: + type->console_type = XBOX360; + type->sub_type = XINPUT_GUITAR_HERO_LIVE; + break; + case PS4_GHLIVE_DONGLE_PID: + type->console_type = PS4; + type->sub_type = LIVE_GUITAR; + break; + case XBOX_360_WT_KIOSK_PID: + type->console_type = XBOX360; + type->sub_type = XINPUT_GUITAR_WT; + break; + } + break; + case XBOX_ONE_CONTROLLER_VID: + if ((pid >= 0x02e0 && pid <= 0x02eF || pid == 0x0b13) && type->console_type != XBOXONE) + { + type->console_type = XINPUTCOMPAT; + type->sub_type = GAMEPAD; + break; + } + break; } } #endif diff --git a/src/shared/main/wii.cpp b/src/shared/main/wii.cpp index d62262edf..dd9d37d41 100644 --- a/src/shared/main/wii.cpp +++ b/src/shared/main/wii.cpp @@ -4,11 +4,12 @@ #include #include "Arduino.h" +#include "commands.h" #include "config.h" #include "controllers.h" #include "io.h" #include "shared_main.h" -#include "commands.h" +#include "state_translation/drums.h" uint8_t wiiBytes; #ifdef INPUT_WII uint8_t wiiPointer = 0; @@ -120,7 +121,7 @@ void initWiiExt(void) { bool initialised = false; bool lastWiiEuphoriaLed = false; bool hadDrum = false; -static uint8_t packetIssueCount = 0; +static uint8_t packetIssueCount = 0; bool wiiDataValid() { return initialised; } @@ -172,10 +173,11 @@ uint8_t* tickWii() { ((data[3] & (0b11100000)) >> 1)); uint8_t note = (data[2] >> 1) & 0x7f; uint8_t channel = ((~data[3]) >> 1) & 0xF; - velocity = 0x7F - velocity; + velocity = (~velocity) & 0x7f; note = 0x7F - note; if (velocity || note) { - onNote(channel, note, velocity); + // map gh notes to their rb counterparts in rb mode + TRANSLATE_GH_MIDI(channel, note, velocity, onNote); } } initialised = true; diff --git a/src/shared/main/wii_emu.cpp b/src/shared/main/wii_emu.cpp index ae5fb2c7e..75736ab4c 100644 --- a/src/shared/main/wii_emu.cpp +++ b/src/shared/main/wii_emu.cpp @@ -9,6 +9,7 @@ #include "shared_main.h" #include "wii.h" #include "wm_crypto.h" +#include #ifdef TICK_WII static volatile unsigned char wm_rand[10]; @@ -37,21 +38,47 @@ const unsigned char id[6] = {0x01, 0x00, 0xA4, 0x20, 0x01, 0x01}; // virtual register static unsigned char twi_reg[256]; - -void initWiiOutput() { +static bool wiiOutEnabled = false; +static uint32_t startTimer = 0; +void initWiiOutput() +{ memset(twi_reg, 0, sizeof(twi_reg)); - twi_reg[0xF0] = 0; // disable encryption + twi_reg[0xF0] = 0; // disable encryption // set id - for (unsigned int i = 0, j = 0xFA; i < 6; i++, j++) { + for (unsigned int i = 0, j = 0xFA; i < 6; i++, j++) + { twi_reg[j] = id[i]; } // set calibration data - for (unsigned int i = 0, j = 0x20; i < 6; i++, j++) { + for (unsigned int i = 0, j = 0x20; i < 6; i++, j++) + { twi_reg[j] = cal_data[i]; } } -void setInputs(uint8_t* inputs, uint8_t len) { +void setInputs(uint8_t *inputs, uint8_t len) +{ +#ifdef WII_OUTPUT_EN_READ + + if (!startTimer) + { + startTimer = millis(); + if (WII_OUTPUT_EN_READ()) + { + wiiOutEnabled = true; + } + } + if (millis() - startTimer > 1000) + { + if (!wiiOutEnabled && (WII_OUTPUT_EN_READ())) + { + reset_usb(); + } + if (wiiOutEnabled && !(WII_OUTPUT_EN_READ())) { + wiiOutEnabled = false; + } + } +#endif memcpy(twi_reg, inputs, len); } /* @@ -62,29 +89,35 @@ Decryption method found at https://web.archive.org/web/20131106235350/http://www */ -unsigned char wm_ror8(unsigned char a, unsigned char b) { +unsigned char wm_ror8(unsigned char a, unsigned char b) +{ // bit shift with roll-over return (a >> b) | ((a << (8 - b)) & 0xFF); } -uint8_t wii_data_format() { +uint8_t wii_data_format() +{ return twi_reg[0xFE]; } -void wm_gentabs() { +void wm_gentabs() +{ unsigned char idx; // check all idx - for (idx = 0; idx < 7; idx++) { + for (idx = 0; idx < 7; idx++) + { // generate test key unsigned char ans[6]; unsigned char tkey[6]; unsigned char t0[10]; - for (unsigned char i = 0; i < 6; i++) { + for (unsigned char i = 0; i < 6; i++) + { ans[i] = pgm_read_byte(&(ans_tbl[idx][i])); } - for (unsigned char i = 0; i < 10; i++) { + for (unsigned char i = 0; i < 10; i++) + { t0[i] = pgm_read_byte(&(sboxes[0][wm_rand[i]])); } @@ -97,13 +130,16 @@ void wm_gentabs() { // compare with actual key bool found = true; - for (unsigned char i = 0; i < 6; i++) { - if (tkey[i] != wm_key[i]) { + for (unsigned char i = 0; i < 6; i++) + { + if (tkey[i] != wm_key[i]) + { found = false; break; } } - if (found) break; // if match, then use this idx + if (found) + break; // if match, then use this idx } // generate encryption from idx key and rand @@ -125,38 +161,53 @@ void wm_gentabs() { wm_sb[6] = pgm_read_byte(&(sboxes[idx + 1][wm_rand[3]])) ^ pgm_read_byte(&(sboxes[idx + 2][wm_rand[5]])); wm_sb[7] = pgm_read_byte(&(sboxes[idx + 1][wm_rand[2]])) ^ pgm_read_byte(&(sboxes[idx + 2][wm_rand[6]])); } -void recv_data(uint8_t addr, uint8_t data) { - if (twi_reg[0xF0] == 0xAA && addr != 0xF0) // if encryption is on +void recv_data(uint8_t addr, uint8_t data) +{ + if (twi_reg[0xF0] == 0xAA && addr != 0xF0) // if encryption is on { // decrypt twi_reg[addr] = (data ^ wm_sb[addr % 8]) + wm_ft[addr % 8]; - } else { + } + else + { twi_reg[addr] = data; } // Euphoria LED #if DEVICE_TYPE == DJ_HERO_TURNTABLE - if (addr == 0xFB) { + if (addr == 0xFB) + { handle_rumble(twi_reg[addr] * 0xFF, RUMBLE_SANTROLLER_EUPHORIA_LED); } #endif } -void recv_end(uint8_t addr, uint8_t len) { - if (addr >= 0x40 && addr < 0x46) { - for (unsigned int i = 0; i < 6; i++) { +void recv_end(uint8_t addr, uint8_t len) +{ + if (addr >= 0x40 && addr < 0x46) + { + for (unsigned int i = 0; i < 6; i++) + { wm_rand[9 - i] = twi_reg[0x40 + i]; } - } else if (addr >= 0x46 && addr < 0x4C) { - for (unsigned int i = 6; i < 10; i++) { + } + else if (addr >= 0x46 && addr < 0x4C) + { + for (unsigned int i = 6; i < 10; i++) + { wm_rand[9 - i] = twi_reg[0x40 + i]; } - for (unsigned int i = 0; i < 2; i++) { + for (unsigned int i = 0; i < 2; i++) + { wm_key[5 - i] = twi_reg[0x40 + 10 + i]; } - } else if (addr >= 0x4C && addr < 0x50) { - for (unsigned int i = 2; i < 6; i++) { + } + else if (addr >= 0x4C && addr < 0x50) + { + for (unsigned int i = 2; i < 6; i++) + { wm_key[5 - i] = twi_reg[0x40 + 10 + i]; } - if (addr + len == 0x50) { + if (addr + len == 0x50) + { // generate decryption once all data is loaded wm_gentabs(); } @@ -164,12 +215,15 @@ void recv_end(uint8_t addr, uint8_t len) { } // Called when the I2C slave is read from -uint8_t req_data(uint8_t addr) { - if (twi_reg[0xF0] == 0xAA) // encryption is on +uint8_t req_data(uint8_t addr) +{ + if (twi_reg[0xF0] == 0xAA) // encryption is on { // encrypt return (twi_reg[addr] - wm_ft[addr % 8]) ^ wm_sb[addr % 8]; - } else { + } + else + { return twi_reg[addr]; } } diff --git a/src/shared/main/wt_drum.cpp b/src/shared/main/wt_drum.cpp index 45e0be750..b0e78893e 100644 --- a/src/shared/main/wt_drum.cpp +++ b/src/shared/main/wt_drum.cpp @@ -3,6 +3,7 @@ #include "Arduino.h" #include "io.h" #include "shared_main.h" +#include "state_translation/drums.h" #ifdef WT_DRUM_SPI_PORT static long lastTick = 0; static int missing = 0; @@ -42,12 +43,12 @@ void tickWtDrum() { uint8_t note = spi_transfer(WT_DRUM_SPI_PORT, 0x00); delayMicroseconds(50); uint8_t velocity = spi_transfer(WT_DRUM_SPI_PORT, 0x00); - onNote(channel, note, velocity); + TRANSLATE_GH_MIDI(channel, note, velocity, onNote); } else if (type == 0x80) { uint8_t note = spi_transfer(WT_DRUM_SPI_PORT, 0x00); delayMicroseconds(50); uint8_t velocity = spi_transfer(WT_DRUM_SPI_PORT, 0x00); - offNote(channel, note, velocity); + TRANSLATE_GH_MIDI(channel, note, velocity, offNote); } delayMicroseconds(10); WT_DRUM_CS_SET(); diff --git a/src/shared/usb/descriptors.cpp b/src/shared/usb/descriptors.cpp index cd7c73f77..81ecaeba6 100644 --- a/src/shared/usb/descriptors.cpp +++ b/src/shared/usb/descriptors.cpp @@ -11,6 +11,7 @@ #include "usbhid.h" #include "util.h" #include "xsm3/xsm3.h" +#include "Arduino.h" // We can't use WideStrings below, as the pico has four byte widestrings, and we need them to be two-byte. @@ -325,6 +326,86 @@ const PROGMEM XBOX_360_CONFIGURATION_MULTI_DESCRIPTOR XBOX360MultiConfigurationD }, SecurityDescriptor : {0x06, 0x41, 0x00, 0x01, 0x01, 0x03}, }; + +const PROGMEM GH_ARCADE_CONFIGURATION_DESCRIPTOR GHArcadeConfigurationDescriptor{ + Config : { + bLength : sizeof(USB_CONFIGURATION_DESCRIPTOR), + bDescriptorType : USB_DESCRIPTOR_CONFIGURATION, + wTotalLength : sizeof(GH_ARCADE_CONFIGURATION_DESCRIPTOR), + bNumInterfaces : 2, + bConfigurationValue : 1, + iConfiguration : NO_DESCRIPTOR, + bmAttributes : + (USB_CONFIG_ATTRIBUTE_RESERVED | USB_CONFIG_ATTRIBUTE_REMOTEWAKEUP), + bMaxPower : USB_CONFIG_POWER_MA(500) + }, + // UnknownDescriptor1 : {0x03, 0x09, 0x00}, + InterfaceHID : { + bLength : sizeof(USB_INTERFACE_DESCRIPTOR), + bDescriptorType : USB_DESCRIPTOR_INTERFACE, + bInterfaceNumber : INTERFACE_ID_Device, + bAlternateSetting : 0, + bNumEndpoints : 1, + bInterfaceClass : HID_INTF, + bInterfaceSubClass : USB_HID_PROTOCOL_NONE, + bInterfaceProtocol : USB_HID_PROTOCOL_NONE, + iInterface : 5 + }, + HIDDescriptor : { + bLength : sizeof(USB_HID_DESCRIPTOR), + bDescriptorType : HID_DESCRIPTOR_HID, + bcdHID : USB_VERSION_BCD(1, 0, 0), + bCountryCode : 0x00, + bNumDescriptors : 1, + bDescrType : HID_DESCRIPTOR_REPORT, + wDescriptorLength : sizeof(gha_descriptor) + }, + EndpointInHID : { + bLength : sizeof(USB_ENDPOINT_DESCRIPTOR), + bDescriptorType : USB_DESCRIPTOR_ENDPOINT, + bEndpointAddress : DEVICE_EPADDR_IN, + bmAttributes : + (USB_TRANSFER_TYPE_INTERRUPT | ENDPOINT_TATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + wMaxPacketSize : 0x40, + bInterval : 1 + }, + InterfaceVendor : { + bLength : sizeof(USB_INTERFACE_DESCRIPTOR), + bDescriptorType : USB_DESCRIPTOR_INTERFACE, + bInterfaceNumber : INTERFACE_ID_Padding, + bAlternateSetting : 0x00, + bNumEndpoints : 3, + bInterfaceClass : 0xFF, + bInterfaceSubClass : 0x01, + bInterfaceProtocol : 0xFF, + iInterface : 6 + }, + ReportINEndpoint21 : { + bLength : sizeof(USB_ENDPOINT_DESCRIPTOR), + bDescriptorType : USB_DESCRIPTOR_ENDPOINT, + bEndpointAddress : 0x82, + bmAttributes : (USB_TRANSFER_TYPE_INTERRUPT | ENDPOINT_TATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + wMaxPacketSize : 0x40, + bInterval : 1, + }, + ReportOUTEndpoint22 : { + bLength : sizeof(USB_ENDPOINT_DESCRIPTOR), + bDescriptorType : USB_DESCRIPTOR_ENDPOINT, + bEndpointAddress : 0x03, + bmAttributes : (USB_TRANSFER_TYPE_INTERRUPT | ENDPOINT_TATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + wMaxPacketSize : 0x40, + bInterval : 1, + }, + ReportINEndpoint23 : { + bLength : sizeof(USB_ENDPOINT_DESCRIPTOR), + bDescriptorType : USB_DESCRIPTOR_ENDPOINT, + bEndpointAddress : 0x84, + bmAttributes : (USB_TRANSFER_TYPE_INTERRUPT | ENDPOINT_TATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + wMaxPacketSize : 0x40, + bInterval : 1, + }, +}; + const PROGMEM OG_XBOX_CONFIGURATION_DESCRIPTOR OGXBOXConfigurationDescriptor = { Config : { bLength : sizeof(USB_CONFIGURATION_DESCRIPTOR), @@ -669,7 +750,7 @@ const PROGMEM uint8_t ps3_feature_01[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const PROGMEM uint8_t ps3_feature_f2[] = { 0xf2, 0xff, 0xff, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // device bdaddr + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // device bdaddr 0x00, 0x03, 0x50, 0x81, 0xd8, 0x01, 0x8a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, @@ -679,7 +760,7 @@ const PROGMEM uint8_t ps3_feature_f2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const PROGMEM uint8_t ps3_feature_f5[] = { 0x01, 0x00, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, // dummy PS3 bdaddr + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, // dummy PS3 bdaddr 0xff, 0xf7, 0x00, 0x03, 0x50, 0x81, 0xd8, 0x01, 0x8a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, @@ -709,24 +790,24 @@ const PROGMEM uint8_t ps3_feature_f8[] = { // Gyro and accel calibration are in here somewhere! const PROGMEM uint8_t ps3_feature_ef[] = { - 0x00, 0xef, 0x04, 0x00, 0x05, 0x03, 0x01, 0xb0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xef, 0x04, 0x00, 0x05, 0x03, 0x01, 0xb0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const PROGMEM uint8_t ps4_feature_config[] = { 0x03, 0x21, 0x27, 0x04, 0x91, PS4_TYPE, 0x2c, 0x56, 0xa0, 0x0f, 0x3d, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x20, 0x0d, 0x0d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PS4_EXTENDED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -AuthPageSizeReport ps4_pagesize_report = { +const PROGMEM AuthPageSizeReport ps4_pagesize_report = { type : 0xF3, u1 : 0x00, size_challenge : 0x38, @@ -734,84 +815,118 @@ AuthPageSizeReport ps4_pagesize_report = { u4 : {0x00, 0x00, 0x00, 0x00} }; +const PROGMEM uint8_t ps5_feature_config[] = { + 0x03, 0x21, 0x28, 0x03, 0xC3, PS4_TYPE, 0x2C, 0x56, + 0x01, 0x00, 0xD0, 0x07, 0x00, 0x80, 0x04, 0x00, + 0x00, 0x80, 0x0D, 0x0D, 0x84, 0x00, 0x00, 0x00, + PS4_EXTENDED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t idle_rate; uint8_t protocol_mode = HID_RPT_PROTOCOL; -bool controlRequestValid(const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t wLength) { +bool controlRequestValid(const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t wLength) +{ // printf("%02x %04x %04x %04x %04x\r\n", requestType, request, wValue, wIndex, wLength); - if (consoleType == UNIVERSAL && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR) && request == 0x81) { + if (consoleType == UNIVERSAL && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR) && request == 0x81) + { return true; } - if (consoleType != OG_XBOX && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR) && request == 6 && wValue == 0x4200) { + if (consoleType != OG_XBOX && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR) && request == 6 && wValue == 0x4200) + { return true; } - if (consoleType == OG_XBOX && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR)) { - if (request == 6 && wValue == 0x4200) { + if (consoleType == OG_XBOX && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR)) + { + if (request == 6 && wValue == 0x4200) + { return true; } - if (request == 1 && wValue == 0x0100) { + if (request == 1 && wValue == 0x0100) + { return true; } - if (request == 1 && wValue == 0x0200) { + if (request == 1 && wValue == 0x0200) + { return true; } } - // Doing this actually *breaks* xb360 on pro micros. - // But its necessary on the pico :/ -#if SUPPORTS_PICO - switch (request) { - case 0x81: - case 0x82: - case 0x87: - case 0x83: - case 0x84: - case 0x86: - return true; + switch (request) + { + case 0x81: + case 0x82: + case 0x87: + case 0x83: + case 0x84: + case 0x86: + return true; } -#endif - if (requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) { - switch (request) { - case HID_REQUEST_SET_PROTOCOL: - case HID_REQUEST_SET_IDLE: - case HID_REQUEST_SET_REPORT: - return true; + if (requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { + switch (request) + { + case HID_REQUEST_SET_PROTOCOL: + case HID_REQUEST_SET_IDLE: + case HID_REQUEST_SET_REPORT: + return true; } - if (request >= COMMAND_REBOOT && request < MAX) { + if (request >= COMMAND_REBOOT && request < MAX) + { return true; } } - if (requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS) && request == USB_REQUEST_GET_INTERFACE) { + if (requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS) && request == USB_REQUEST_GET_INTERFACE) + { return true; } - if (requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS) && request == USB_REQUEST_GET_STATUS) { + if (requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS) && request == USB_REQUEST_GET_STATUS) + { return true; } - if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS) && request == USB_REQUEST_SET_INTERFACE) { + if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS) && request == USB_REQUEST_SET_INTERFACE) + { return true; } - if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) { - switch (request) { - case HID_REQUEST_GET_PROTOCOL: - case HID_REQUEST_GET_IDLE: - case HID_REQUEST_GET_REPORT: - return true; - } - if (request >= COMMAND_REBOOT && request < MAX) { + if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { + switch (request) + { + case HID_REQUEST_GET_PROTOCOL: + case HID_REQUEST_GET_IDLE: + case HID_REQUEST_GET_REPORT: + return true; + } + if (request >= COMMAND_REBOOT && request < MAX) + { return true; } - } else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR)) { - if (request == HID_REQUEST_GET_REPORT && wIndex == INTERFACE_ID_Device && wValue == VIBRATION_CAPABILITIES_WVALUE) { + } + else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR)) + { + if (request == HID_REQUEST_GET_REPORT && wIndex == INTERFACE_ID_Device && wValue == VIBRATION_CAPABILITIES_WVALUE) + { return true; - } else if (request == REQ_GET_OS_FEATURE_DESCRIPTOR && wIndex == DESC_EXTENDED_PROPERTIES_DESCRIPTOR && wValue == INTERFACE_ID_Config) { + } + else if (request == REQ_GET_OS_FEATURE_DESCRIPTOR && wIndex == DESC_EXTENDED_PROPERTIES_DESCRIPTOR && wValue == INTERFACE_ID_Config) + { return true; - } else if (request == HID_REQUEST_GET_REPORT && wIndex == INTERFACE_ID_Device && wValue == INPUT_CAPABILITIES_WVALUE) { + } + else if (request == HID_REQUEST_GET_REPORT && wIndex == INTERFACE_ID_Device && wValue == INPUT_CAPABILITIES_WVALUE) + { return true; } - } else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && (consoleType == WINDOWS || consoleType == XBOX360) && request == HID_REQUEST_GET_REPORT && wIndex == 0x0000 && wValue == SERIAL_NUMBER_WVALUE) { + } + else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && (consoleType == WINDOWS || consoleType == XBOX360) && request == HID_REQUEST_GET_REPORT && wIndex == 0x0000 && wValue == SERIAL_NUMBER_WVALUE) + { return true; - } else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && request == REQ_GET_OS_FEATURE_DESCRIPTOR && wIndex == DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR) { + } + else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && request == REQ_GET_OS_FEATURE_DESCRIPTOR && wIndex == DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR) + { return true; - } else if (consoleType == UNIVERSAL && request == USB_REQUEST_CLEAR_FEATURE && (wIndex == DEVICE_EPADDR_IN || wIndex == DEVICE_EPADDR_OUT)) { + } + else if (consoleType == UNIVERSAL && request == USB_REQUEST_CLEAR_FEATURE && (wIndex == DEVICE_EPADDR_IN || wIndex == DEVICE_EPADDR_OUT)) + { return true; } return false; @@ -819,133 +934,150 @@ bool controlRequestValid(const uint8_t requestType, const uint8_t request, const uint8_t ps3_id_id = 4; bool cleared_input = false; bool cleared_output = false; -uint16_t controlRequest(const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t wLength, uint8_t *requestBuffer, bool *status) { +uint16_t controlRequest(const uint8_t requestType, const uint8_t request, const uint16_t wValue, const uint16_t wIndex, const uint16_t wLength, uint8_t *requestBuffer, bool *status) +{ // printf("%02x %04x %04x %04x %04x\r\n", requestType, request, wValue, wIndex, wLength); #if DEVICE_TYPE_IS_GAMEPAD - if (consoleType != OG_XBOX && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR) && request == 6 && wValue == 0x4200) { - consoleType = OG_XBOX; - reset_usb(); - return 0; - } - if (consoleType == OG_XBOX && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR)) { - if (request == 6 && wValue == 0x4200) { + if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR) && (consoleType == UNIVERSAL || consoleType == OG_XBOX)) + { + seen_og_xbox = true; + if (request == 6 && wValue == 0x4200) + { memcpy_P(requestBuffer, &DukeXIDDescriptor, sizeof(DukeXIDDescriptor)); return sizeof(DukeXIDDescriptor); } - if (request == 1 && wValue == 0x0100) { + if (request == 1 && wValue == 0x0100) + { memcpy_P(requestBuffer, &DukeXIDInputCapabilities, sizeof(DukeXIDInputCapabilities)); return sizeof(DukeXIDInputCapabilities); } - if (request == 1 && wValue == 0x0200) { + if (request == 1 && wValue == 0x0200) + { memcpy_P(requestBuffer, &DukeXIDVibrationCapabilities, sizeof(DukeXIDVibrationCapabilities)); return sizeof(DukeXIDVibrationCapabilities); } } #endif - if (consoleType == XBOX360 && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR) && request == 0x83) { - if (xbox_360_state == Auth1) { + if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR) && request == 0x83) + { + if (xbox_360_state == Auth1) + { xbox_360_state = Auth2; - } else if (xbox_360_state == Auth2) { + } + else if (xbox_360_state == Auth2) + { xbox_360_state = Auth3; - } else if (xbox_360_state == Auth3) { + } + else if (xbox_360_state == Auth3) + { xbox_360_state = Authenticated; handle_auth_led(); + if (consoleType != XBOX360) + { + consoleType = XBOX360; + reset_after_360 = millis() + 100; + } } } - if (seen_windows_xb1 && !(requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && request == REQ_GET_OS_FEATURE_DESCRIPTOR && wIndex == DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR)) { + if (seen_windows_xb1 && !(requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && request == REQ_GET_OS_FEATURE_DESCRIPTOR && wIndex == DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR)) + { seen_windows = true; } - if (requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) { - if (request == COMMAND_REBOOT) { + if (requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { + if (request == COMMAND_REBOOT) + { reboot(); } - if (request == COMMAND_JUMP_BOOTLOADER) { + if (request == COMMAND_JUMP_BOOTLOADER) + { bootloader(); } - if (request >= COMMAND_REBOOT && request < MAX) { + if (request >= COMMAND_REBOOT && request < MAX) + { bool success; return handle_serial_command(request, wValue, requestBuffer, &success); } } - if (requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS) && request == USB_REQUEST_GET_INTERFACE) { + if (requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS) && request == USB_REQUEST_GET_INTERFACE) + { ((uint8_t *)requestBuffer)[0] = 0; return 1; } - if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS) && request == USB_REQUEST_SET_INTERFACE) { + if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS) && request == USB_REQUEST_SET_INTERFACE) + { return 0; } #if DEVICE_TYPE_IS_GAMEPAD - if (consoleType == UNIVERSAL && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR) && request == 0x81) { +#if SUPPORTS_PICO + switch (request) + { + case 0x81: + uint8_t serial[0x0C]; + read_serial(serial, sizeof(serial)); + xsm3_set_vid_pid(serial, ARDWIINO_VID, ARDWIINO_PID); + xsm3_initialise_state(); + xsm3_set_identification_data(xsm3_id_data_ms_controller); + memcpy(requestBuffer, xsm3_id_data_ms_controller, sizeof(xsm3_id_data_ms_controller)); + return sizeof(xsm3_id_data_ms_controller); + case 0x82: + xsm3_do_challenge_init((uint8_t *)requestBuffer); + return 0; + case 0x87: + xsm3_do_challenge_verify((uint8_t *)requestBuffer); + return 0; + case 0x84: + return 0; + case 0x83: + memcpy(requestBuffer, xsm3_challenge_response, sizeof(xsm3_challenge_response)); + return wLength; + case 0x86: + short state = 2; // 1 = in-progress, 2 = complete + memcpy(requestBuffer, &state, sizeof(state)); + return sizeof(state); + } +#else + if (consoleType == UNIVERSAL && requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR) && request == 0x81) + { consoleType = XBOX360; reset_usb(); return 0; } -#ifdef KV_KEY_ARRAY - switch (request) { - case 0x81: - uint8_t serial[0x0C]; - read_serial(serial, sizeof(serial)); - xsm3_set_vid_pid(serial, xbox_360_vid, xbox_360_pid); - xsm3_initialise_state(); - xsm3_set_identification_data(xsm3_id_data_ms_controller); - memcpy(requestBuffer, xsm3_id_data_ms_controller, sizeof(xsm3_id_data_ms_controller)); - return sizeof(xsm3_id_data_ms_controller); - case 0x82: - xsm3_do_challenge_init((uint8_t *)requestBuffer); - return 0; - case 0x87: - xsm3_do_challenge_verify((uint8_t *)requestBuffer); - return 0; - case 0x84: - return 0; - case 0x83: - memcpy(requestBuffer, xsm3_challenge_response, sizeof(xsm3_challenge_response)); - return wLength; - case 0x86: - short state = 2; // 1 = in-progress, 2 = complete - memcpy(requestBuffer, &state, sizeof(state)); - return sizeof(state); - } -#elif USB_HOST_STACK - switch (request) { - case 0x81: - case 0x82: - case 0x87: - case 0x84: - case 0x83: - case 0x86: - USB_Device_Type_t type = get_device_address_for(XBOX360); - return transfer_with_usb_controller(type.dev_addr, requestType, request, wValue, wIndex, wLength, requestBuffer, status); - } -#else - switch (request) { - case 0x81: - case 0x82: - case 0x87: - case 0x84: - case 0x83: - case 0x86: - return 0; + switch (request) + { + case 0x81: + case 0x82: + case 0x87: + case 0x84: + case 0x83: + case 0x86: + return 0; } #endif #endif - if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) { + if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { #if DEVICE_TYPE_IS_GAMEPAD // PS3s request this as some form of controller id - if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x0300 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT && wLength == 0x08) { + if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x0300 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) + { // Pro instruments use a different init flow #if DEVICE_TYPE_IS_PRO - if (proButtonsEnabled) { + if (proButtonsEnabled) + { memcpy_P(requestBuffer, enabled_response[ps3_id_id], sizeof(enabled_response[ps3_id_id])); - } else { + } + else + { memcpy_P(requestBuffer, disabled_response[ps3_id_id], sizeof(disabled_response[ps3_id_id])); } ps3_id_id++; - if (ps3_id_id > 4) ps3_id_id = 4; + if (ps3_id_id > 4) + ps3_id_id = 4; return 8; #else memcpy_P(requestBuffer, ps3_init, sizeof(ps3_init)); @@ -953,40 +1085,53 @@ uint16_t controlRequest(const uint8_t requestType, const uint8_t request, const #endif } // Fakemote sends this, so we know to jump to PS3 mode - if (consoleType == UNIVERSAL && wValue == 0x03f2 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT && wLength == 0x11) { - consoleType = PS3; - reset_usb(); + if ((consoleType == UNIVERSAL || consoleType == WINDOWS) && wValue == 0x03f2 && (wIndex == INTERFACE_ID_Device || wIndex == INTERFACE_ID_Config) && request == HID_REQUEST_GET_REPORT && wLength == 0x11) + { + if (RPCS3_COMPAT) + { + consoleType = PS3; + reset_usb(); + } } // RPCS3 sends this. Jump any devices with RPCS3 compat enabled - if ((consoleType == UNIVERSAL || consoleType == WINDOWS) && wValue == 0x03f2 && wIndex == INTERFACE_ID_Config && request == HID_REQUEST_GET_REPORT) { - if (RPCS3_COMPAT) { + if ((consoleType == UNIVERSAL || consoleType == WINDOWS) && wValue == 0x03f2 && wIndex == INTERFACE_ID_Config && request == HID_REQUEST_GET_REPORT) + { + if (RPCS3_COMPAT) + { consoleType = PS3; reset_usb(); } seen_rpcs3 = true; } - if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03f8 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) { + if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03f8 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) + { memcpy_P(requestBuffer, ps3_feature_f8, sizeof(ps3_feature_f8)); requestBuffer[7] = ef_byte; return sizeof(ps3_feature_f8); } - if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03f7 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) { + if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03f7 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) + { memcpy_P(requestBuffer, ps3_feature_f7, sizeof(ps3_feature_f7)); return sizeof(ps3_feature_f7); } - if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03f2 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) { + if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03f2 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) + { memcpy_P(requestBuffer, ps3_feature_f2, sizeof(ps3_feature_f2)); return sizeof(ps3_feature_f2); } - if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03f5 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) { + if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03f5 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) + { memcpy_P(requestBuffer, ps3_feature_f5, sizeof(ps3_feature_f5)); - if (f5_state == 0) { + if (f5_state == 0) + { /* * First request, tell that the bdaddr is not the one of the PS3. */ f5_state = 1; - } else { + } + else + { /* * Next requests, tell that the bdaddr is the one of the PS3. */ @@ -994,169 +1139,277 @@ uint16_t controlRequest(const uint8_t requestType, const uint8_t request, const } return sizeof(ps3_feature_f5); } - if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03ef && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) { + if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03ef && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) + { memcpy_P(requestBuffer, ps3_feature_ef, sizeof(ps3_feature_ef)); requestBuffer[7] = ef_byte; return sizeof(ps3_feature_ef); } // PS3 sends this for a gamepad - if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x0301 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT && wLength == 0x40) { + if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x0301 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT && wLength == 0x40) + { memcpy_P(requestBuffer, ps3_feature_01, sizeof(ps3_feature_01)); return sizeof(ps3_feature_01); } // PS3 and PS4 send this - if (consoleType == UNIVERSAL && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT && wValue == 0x0303) { + if (consoleType == UNIVERSAL && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT && wValue == 0x0303) + { + seen_ps4 = true; // PS3 Drums and Guitars get used on both consoles, so we can jump straight to PS3 mode #if DEVICE_TYPE_IS_INSTRUMENT && !SUPPORTS_PS4 consoleType = PS3; reset_usb(); #else - // the PS3 and PS4 will end up here. PS4 mode will jump back to PS3 mode on a PS3 later. - consoleType = PS4; - reset_usb(); + if (wLength == sizeof(ps4_feature_config)) + { + consoleType = PS4; + reset_usb(); + } + else + { + consoleType = PS3; + reset_usb(); + } + #endif } - if (consoleType == PS4 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) { - switch (wValue) { - case 0x0303: - seen_ps4 = true; - memcpy_P(requestBuffer, ps4_feature_config, sizeof(ps4_feature_config)); - return sizeof(ps4_feature_config); + if (consoleType == PS4 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) + { + switch (wValue) + { + case 0x0303: + seen_ps4 = true; + memcpy_P(requestBuffer, ps4_feature_config, sizeof(ps4_feature_config)); + return sizeof(ps4_feature_config); #if USB_HOST_STACK - case GET_RESPONSE: { - return transfer_with_usb_controller(get_device_address_for(PS4).dev_addr, requestType, request, wValue, wIndex, wLength, requestBuffer, status); - } - case GET_AUTH_STATUS: { - return transfer_with_usb_controller(get_device_address_for(PS4).dev_addr, requestType, request, wValue, wIndex, wLength, requestBuffer, status); + case GET_RESPONSE: + { + + return transfer_with_usb_controller(get_device_address_for(PS4), requestType, request, wValue, wLength, requestBuffer, status); + } + case GET_AUTH_STATUS: + { + return transfer_with_usb_controller(get_device_address_for(PS4), requestType, request, wValue, wLength, requestBuffer, status); + } + case GET_AUTH_PAGE_SIZE: + { + // Don't start the auth process until we see a controller + if (get_device_address_for(PS4).dev_addr == 0) + { + return 0; } - case GET_AUTH_PAGE_SIZE: { - // Don't start the auth process until we see a controller - if (get_device_address_for(PS4).dev_addr == 0) { - return 0; - } - // Attempt to read the page size from the connected controller + // Attempt to read the page size from the connected controller + uint32_t len = transfer_with_usb_controller(get_device_address_for(PS4), requestType, request, wValue, wLength, requestBuffer, NULL); + if (!len) + { // On a DS4, this will fail but we have the default page size report for that scenario. - transfer_with_usb_controller(get_device_address_for(PS4).dev_addr, (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS), HID_REQUEST_GET_REPORT, GET_AUTH_PAGE_SIZE, INTERFACE_ID_Device, sizeof(AuthPageSizeReport), (uint8_t *)&ps4_pagesize_report, NULL); memcpy_P(requestBuffer, &ps4_pagesize_report, sizeof(ps4_pagesize_report)); - return sizeof(ps4_pagesize_report); + len = sizeof(ps4_pagesize_report); } + return len; + } #else - case GET_AUTH_PAGE_SIZE: { - memcpy_P(requestBuffer, &ps4_pagesize_report, sizeof(ps4_pagesize_report)); - return sizeof(ps4_pagesize_report); - } + case GET_AUTH_PAGE_SIZE: + { + memcpy_P(requestBuffer, &ps4_pagesize_report, sizeof(ps4_pagesize_report)); + return sizeof(ps4_pagesize_report); + } #endif } } - if (wValue == 0x0101 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT && wLength == 0x80) { + if (consoleType == PS5 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT) + { + switch (wValue) + { + case 0x0303: + seen_ps4 = true; + memcpy_P(requestBuffer, ps5_feature_config, sizeof(ps5_feature_config)); + return sizeof(ps5_feature_config); + +#if USB_HOST_STACK + case GET_RESPONSE: + { + return transfer_with_usb_controller(get_device_address_for(PS5), requestType, request, wValue, wLength, requestBuffer, status); + } + case GET_AUTH_STATUS: + { + return transfer_with_usb_controller(get_device_address_for(PS5), requestType, request, wValue, wLength, requestBuffer, status); + } +#endif + } + } + if (wValue == 0x0101 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT && wLength == 0x80) + { return tick_inputs(requestBuffer, NULL, consoleType); } - if (consoleType == OG_XBOX && wValue == 0x0100 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT && wLength == sizeof(OG_XBOX_REPORT)) { + if (consoleType == OG_XBOX && wValue == 0x0100 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_GET_REPORT && wLength == sizeof(OG_XBOX_REPORT)) + { return tick_inputs(requestBuffer, NULL, consoleType); } #endif bool test = true; - uint8_t size = handle_serial_command(request, wValue, requestBuffer, &test); - if (test) { + uint16_t size = handle_serial_command(request, wValue, requestBuffer, &test); + if (test) + { return size; } - } else if (request == HID_REQUEST_SET_REPORT && wValue == SET_CHALLENGE && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) { + } + else if (request == HID_REQUEST_SET_REPORT && consoleType == PS4 && wValue == SET_CHALLENGE && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { +#if USB_HOST_STACK + return transfer_with_usb_controller(get_device_address_for(PS4), requestType, request, wValue, wLength, requestBuffer, status); +#else + return 0; +#endif + } + else if (request == HID_REQUEST_SET_REPORT && consoleType == PS5 && wValue == SET_CHALLENGE && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { #if USB_HOST_STACK - return transfer_with_usb_controller(get_device_address_for(PS4).dev_addr, requestType, request, wValue, wIndex, wLength, requestBuffer, status); + return transfer_with_usb_controller(get_device_address_for(PS5), requestType, request, wValue, wLength, requestBuffer, status); #else return 0; #endif - } else if (request == HID_REQUEST_SET_REPORT && wValue == 0x03F2 && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) { + } + else if (request == HID_REQUEST_SET_REPORT && wValue == 0x03F2 && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { return 1; - } else if (request == HID_REQUEST_SET_REPORT && wValue == 0x03F4 && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) { + } + else if (request == HID_REQUEST_SET_REPORT && wValue == 0x03F4 && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { // pademu sends this, so we know to jump to PS3 mode - if (consoleType == UNIVERSAL && wLength == 0x04) { + if (consoleType == UNIVERSAL && wLength == 0x04) + { consoleType = PS3; reset_usb(); } return 1; - } else if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03ef && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_SET_REPORT) { + } + else if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03ef && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_SET_REPORT) + { ef_byte = requestBuffer[6]; return 1; - } else if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03f5 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_SET_REPORT) { + } + else if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x03f5 && wIndex == INTERFACE_ID_Device && request == HID_REQUEST_SET_REPORT) + { memcpy(master_bd_addr, requestBuffer + 2, sizeof(master_bd_addr)); printf("Master bd address set\r\n"); return 1; - } else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR)) { - if (request == HID_REQUEST_GET_REPORT && wIndex == INTERFACE_ID_Device && wValue == VIBRATION_CAPABILITIES_WVALUE) { + } + else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_VENDOR)) + { + if (request == HID_REQUEST_GET_REPORT && wIndex == INTERFACE_ID_Device && wValue == VIBRATION_CAPABILITIES_WVALUE) + { memcpy_P(requestBuffer, &XInputVibrationCapabilities, sizeof(XInputVibrationCapabilities)); return sizeof(XInputVibrationCapabilities); - } else if (request == REQ_GET_OS_FEATURE_DESCRIPTOR && wIndex == DESC_EXTENDED_PROPERTIES_DESCRIPTOR) { + } + else if (request == REQ_GET_OS_FEATURE_DESCRIPTOR && wIndex == DESC_EXTENDED_PROPERTIES_DESCRIPTOR) + { memcpy_P(requestBuffer, &ExtendedIDs, ExtendedIDs.TotalLength); return ExtendedIDs.TotalLength; - } else if (request == HID_REQUEST_GET_REPORT && wIndex == INTERFACE_ID_Device && wValue == INPUT_CAPABILITIES_WVALUE) { + } + else if (request == HID_REQUEST_GET_REPORT && wIndex == INTERFACE_ID_Device && wValue == INPUT_CAPABILITIES_WVALUE) + { memcpy_P(requestBuffer, &XInputInputCapabilities, sizeof(XInputInputCapabilities)); + + if (DEVICE_TYPE_IS_PRO_GUITAR) + { + XInputInputCapabilities_t *caps = (XInputInputCapabilities_t *)requestBuffer; + if (proGuitarType == ROCK_BAND_PRO_GUITAR_MUSTANG) + { + caps->leftThumbY = XBOX_360_MUSTANG_PID; + } + if (proGuitarType == ROCK_BAND_PRO_GUITAR_SQUIRE) + { + caps->leftThumbY = XBOX_360_SQUIRE_MPA_PID; + } + } return sizeof(XInputInputCapabilities); } - } else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && (consoleType == WINDOWS || consoleType == XBOX360) && request == HID_REQUEST_GET_REPORT && wIndex == 0x0000 && wValue == SERIAL_NUMBER_WVALUE) { + } + else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && (consoleType == WINDOWS || consoleType == XBOX360) && request == HID_REQUEST_GET_REPORT && wIndex == 0x0000 && wValue == SERIAL_NUMBER_WVALUE) + { uint32_t serial = micros(); memcpy(requestBuffer, &serial, sizeof(serial)); return sizeof(XInputSerialNumber_t); - } else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && request == REQ_GET_OS_FEATURE_DESCRIPTOR && wIndex == DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR) { + } + else if (requestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && request == REQ_GET_OS_FEATURE_DESCRIPTOR && wIndex == DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR) + { seen_windows_xb1 = true; memcpy_P(requestBuffer, &DevCompatIDs, sizeof(OS_COMPATIBLE_ID_DESCRIPTOR)); -#if USB_HOST_STACK - if (consoleType == XBOXONE) { + if (consoleType == XBOXONE) + { memcpy_P(requestBuffer, &DevCompatIDsOne, sizeof(DevCompatIDsOne)); return sizeof(DevCompatIDsOne); - } else -#endif - if (consoleType == WINDOWS || consoleType == XBOX360) { + } + else if (consoleType == WINDOWS || consoleType == XBOX360) + { OS_COMPATIBLE_ID_DESCRIPTOR *compat = (OS_COMPATIBLE_ID_DESCRIPTOR *)requestBuffer; compat->TotalSections = 4; compat->TotalLength = sizeof(OS_COMPATIBLE_ID_DESCRIPTOR); return sizeof(OS_COMPATIBLE_ID_DESCRIPTOR); - } else if (consoleType == PS3 || consoleType == WII_RB) { + } +#if DEVICE_TYPE != GUITAR_HERO_GUITAR + else if (consoleType == PS3 || consoleType == WII_RB) + { memcpy_P(requestBuffer, &DevCompatIDsPS3, sizeof(OS_COMPATIBLE_ID_DESCRIPTOR_SINGLE)); return sizeof(OS_COMPATIBLE_ID_DESCRIPTOR_SINGLE); - } else if (consoleType != UNIVERSAL) { + } +#endif + else if (consoleType != UNIVERSAL) + { return 0; } memcpy_P(requestBuffer, &DevCompatIDsUniversal, sizeof(DevCompatIDsUniversal)); return sizeof(DevCompatIDsUniversal); - } else if (request == HID_REQUEST_SET_PROTOCOL && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) { + } + else if (request == HID_REQUEST_SET_PROTOCOL && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { protocol_mode = (uint8_t)wValue; return 0; - } else if (request == HID_REQUEST_SET_IDLE && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) { + } + else if (request == HID_REQUEST_SET_IDLE && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { idle_rate = (wValue >> 8) & 0xff; return 0; - } else if (consoleType == UNIVERSAL && request == USB_REQUEST_CLEAR_FEATURE && (wIndex == DEVICE_EPADDR_IN || wIndex == DEVICE_EPADDR_OUT)) { + } + else if (consoleType == UNIVERSAL && request == USB_REQUEST_CLEAR_FEATURE && (wIndex == DEVICE_EPADDR_IN || wIndex == DEVICE_EPADDR_OUT)) + { // Switch clears a halt on both endpoints cleared_input |= wIndex == DEVICE_EPADDR_IN; cleared_output |= wIndex == DEVICE_EPADDR_OUT; - if (cleared_input && cleared_output) { + if (cleared_input && cleared_output) + { consoleType = SWITCH; reset_usb(); return 0; } - } else if (request == HID_REQUEST_SET_REPORT && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) { + } + else if (request == HID_REQUEST_SET_REPORT && requestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_RECIPIENT_INTERFACE | USB_SETUP_TYPE_CLASS)) + { const uint8_t reportType = (wValue >> 8); const uint8_t reportId = (wValue & 0xFF); hid_set_report((uint8_t *)requestBuffer, wLength, reportType, reportId); #if DEVICE_TYPE_IS_PRO - if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x0300 && wIndex == INTERFACE_ID_Device && wLength == 0x28) { + if ((consoleType == PS3 || consoleType == IOS_FESTIVAL) && wValue == 0x0300 && wIndex == INTERFACE_ID_Device && wLength == 0x28) + { // for (int i = 0; i < 0x28; i++) { // printf("%02x, ", requestBuffer[i]); // } // printf("\r\n"); - switch (requestBuffer[2]) { - case 0x89: - printf("MIDI data enabled\r\n"); - proButtonsEnabled = true; - ps3_id_id = 0; - break; - case 0x81: - printf("MIDI data disabled\r\n"); - proButtonsEnabled = false; - ps3_id_id = 0; - break; + switch (requestBuffer[2]) + { + case 0x89: + printf("MIDI data enabled\r\n"); + proButtonsEnabled = true; + ps3_id_id = 0; + break; + case 0x81: + printf("MIDI data disabled\r\n"); + proButtonsEnabled = false; + ps3_id_id = 0; + break; } } #endif @@ -1167,227 +1420,399 @@ uint16_t controlRequest(const uint8_t requestType, const uint8_t request, const bool seen_windows_desc = false; uint16_t descriptorRequest(const uint16_t wValue, const uint16_t wIndex, - void *descriptorBuffer) { + void *descriptorBuffer) +{ const uint8_t descriptorType = (wValue >> 8); const uint8_t descriptorNumber = (wValue & 0xFF); + // printf("desc: %02x %02x\r\n", descriptorType, descriptorNumber); #if DEVICE_TYPE_IS_GAMEPAD -#if USB_HOST_STACK - if (consoleType == UNIVERSAL && seen_windows_xb1 && descriptorType != HID_DESCRIPTOR_REPORT) { + if (consoleType == UNIVERSAL && seen_windows_xb1 && descriptorType != HID_DESCRIPTOR_REPORT) + { seen_windows_desc = true; } - if (consoleType == UNIVERSAL && seen_windows_xb1 && descriptorType == HID_DESCRIPTOR_REPORT) { - if (seen_windows_desc) { - if (WINDOWS_USES_XINPUT) { + if (consoleType == UNIVERSAL && seen_windows_xb1 && descriptorType == HID_DESCRIPTOR_REPORT) + { + if (seen_windows_desc) + { + if (WINDOWS_USES_XINPUT) + { set_console_type(WINDOWS); } - } else { + } + else + { set_console_type(XBOXONE); } } -#else - if (WINDOWS_USES_XINPUT && consoleType == UNIVERSAL && seen_windows_xb1 && descriptorType != HID_DESCRIPTOR_REPORT) { - set_console_type(WINDOWS); - } - -#endif #endif descriptor_requested = true; uint16_t size = NO_DESCRIPTOR; - switch (descriptorType) { - case USB_DESCRIPTOR_DEVICE: { - read_device_desc = true; - size = sizeof(USB_DEVICE_DESCRIPTOR); - memcpy_P(descriptorBuffer, &deviceDescriptor, size); - USB_DEVICE_DESCRIPTOR *dev = (USB_DEVICE_DESCRIPTOR *)descriptorBuffer; + switch (descriptorType) + { + case USB_DESCRIPTOR_DEVICE: + { + read_device_desc = true; + size = sizeof(USB_DEVICE_DESCRIPTOR); + memcpy_P(descriptorBuffer, &deviceDescriptor, size); + USB_DEVICE_DESCRIPTOR *dev = (USB_DEVICE_DESCRIPTOR *)descriptorBuffer; #if DEVICE_TYPE_IS_GAMEPAD - if (consoleType == SWITCH) { - dev->idVendor = HORI_VID; - dev->idProduct = HORI_POKKEN_TOURNAMENT_DX_PRO_PAD_PID; - } else if (consoleType == XBOX360) { - dev->idVendor = xbox_360_vid; - dev->idProduct = xbox_360_pid; - } else if (consoleType == OG_XBOX) { - dev->idVendor = 0x045E; - dev->idProduct = 0x0289; - } -#if USB_HOST_STACK - else if (consoleType == XBOXONE) { - dev->idVendor = XBOX_ONE_CONTROLLER_VID; - dev->idProduct = XBOX_ONE_CONTROLLER_PID; - dev->bDeviceClass = 0xff; - dev->bDeviceSubClass = 0x47; - dev->bDeviceProtocol = 0xd0; - } -#endif - else if (consoleType == PS4) { -#if DEVICE_TYPE_IS_INSTRUMENT - dev->idVendor = XBOX_REDOCTANE_VID; - dev->idProduct = PS4_GHLIVE_DONGLE_PID; -#else - dev->idVendor = PS4_VID; - dev->idProduct = PS4_PID; -#endif - } else if (consoleType == IOS_FESTIVAL) { - dev->idVendor = SONY_VID; - dev->idProduct = SONY_DS3_PID; - } + if (consoleType == SWITCH) + { + dev->idVendor = HORI_VID; + dev->idProduct = HORI_POKKEN_TOURNAMENT_DX_PRO_PAD_PID; + } + else if (consoleType == XBOX360) + { + dev->idVendor = ARDWIINO_VID; + dev->idProduct = ARDWIINO_PID; + } + else if (consoleType == OG_XBOX) + { + dev->idVendor = 0x045E; + dev->idProduct = 0x0289; + } + else if (consoleType == XBOXONE) + { + dev->idVendor = XBOX_ONE_CONTROLLER_VID; + dev->idProduct = XBOX_ONE_CONTROLLER_PID; + dev->bDeviceClass = 0xff; + dev->bDeviceSubClass = 0x47; + dev->bDeviceProtocol = 0xd0; + } + else if (consoleType == PS4) + { + dev->idVendor = PS4_VID; + dev->idProduct = PS4_PID; + } + else if (consoleType == PS5) + { + dev->idVendor = 0x2B81; + dev->idProduct = 0x0101; + } + else if (consoleType == IOS_FESTIVAL) + { + dev->idVendor = SONY_VID; + dev->idProduct = SONY_DS3_PID; + } #ifdef WII_TYPE - else if (consoleType == WII_RB) { - dev->idVendor = HARMONIX_VID; - dev->idProduct = WII_TYPE; + else if (consoleType == WII_RB) + { + dev->idVendor = HARMONIX_VID; + dev->idProduct = WII_TYPE; + if (DEVICE_TYPE_IS_PRO_GUITAR) + { + if (proGuitarType == ROCK_BAND_PRO_GUITAR_MUSTANG) + { + dev->idProduct = WII_MUSTANG_PID; + } + if (proGuitarType == ROCK_BAND_PRO_GUITAR_SQUIRE) + { + dev->idProduct = WII_SQUIRE_MPA_PID; + } } + } #endif #ifdef PS3_TYPE - else if (consoleType == PS3) { - dev->idVendor = REDOCTANE_VID; - dev->idProduct = PS3_TYPE; + else if (consoleType == PS3) + { + dev->idVendor = REDOCTANE_VID; + dev->idProduct = PS3_TYPE; + if (DEVICE_TYPE_IS_PRO_GUITAR) + { + if (proGuitarType == ROCK_BAND_PRO_GUITAR_MUSTANG) + { + dev->idProduct = PS3_MUSTANG_PID; + } + if (proGuitarType == ROCK_BAND_PRO_GUITAR_SQUIRE) + { + dev->idProduct = PS3_SQUIRE_MPA_PID; + } } + } #elif DEVICE_TYPE == GAMEPAD - else if (consoleType == PS3) { - dev->idVendor = SONY_VID; - dev->idProduct = SONY_DS3_PID; - } + else if (consoleType == PS3) + { + dev->idVendor = SONY_VID; + dev->idProduct = SONY_DS3_PID; + } #endif #endif #if DEVICE_TYPE == ROCK_BAND_GUITAR || DEVICE_TYPE == GUITAR_HERO_GUITAR - if (consoleType == FNF) { - dev->idVendor = PDP_VID; - dev->idProduct = XBOX_ONE_JAG_PID; - } + if (consoleType == FNF) + { + dev->idVendor = PDP_VID; + dev->idProduct = XBOX_ONE_JAG_PID; + } #endif - break; + if (consoleType == ARCADE) + { + dev->idVendor = 0x0c70; + dev->idProduct = 0x0777; } - case USB_DESCRIPTOR_CONFIGURATION: { + break; + } + case USB_DESCRIPTOR_CONFIGURATION: + { #if CONSOLE_TYPE == MIDI_ID - size = sizeof(MIDI_CONFIGURATION_DESCRIPTOR); - memcpy_P(descriptorBuffer, &MIDIConfigurationDescriptor, size); + size = sizeof(MIDI_CONFIGURATION_DESCRIPTOR); + memcpy_P(descriptorBuffer, &MIDIConfigurationDescriptor, size); #elif DEVICE_TYPE_IS_KEYBOARD - size = sizeof(UNIVERSAL_CONFIGURATION_DESCRIPTOR); - memcpy_P(descriptorBuffer, &UniversalConfigurationDescriptor, size); + size = sizeof(UNIVERSAL_CONFIGURATION_DESCRIPTOR); + memcpy_P(descriptorBuffer, &UniversalConfigurationDescriptor, size); #else -#if USB_HOST_STACK - if (consoleType == XBOXONE) { - size = sizeof(XBOX_ONE_CONFIGURATION_DESCRIPTOR); - memcpy_P(descriptorBuffer, &XBOXOneConfigurationDescriptor, size); - } else -#endif - if (consoleType == WINDOWS || consoleType == XBOX360) { - size = sizeof(XBOX_360_CONFIGURATION_DESCRIPTOR); - memcpy_P(descriptorBuffer, &XBOX360ConfigurationDescriptor, size); - } else if (consoleType == OG_XBOX) { - size = sizeof(OG_XBOX_CONFIGURATION_DESCRIPTOR); - memcpy_P(descriptorBuffer, &OGXBOXConfigurationDescriptor, size); - } else { - size = sizeof(UNIVERSAL_CONFIGURATION_DESCRIPTOR); - memcpy_P(descriptorBuffer, &UniversalConfigurationDescriptor, size); - UNIVERSAL_CONFIGURATION_DESCRIPTOR *desc = (UNIVERSAL_CONFIGURATION_DESCRIPTOR *)descriptorBuffer; + if (consoleType == XBOXONE) + { + size = sizeof(XBOX_ONE_CONFIGURATION_DESCRIPTOR); + memcpy_P(descriptorBuffer, &XBOXOneConfigurationDescriptor, size); + } + else if (consoleType == WINDOWS || consoleType == XBOX360) + { + size = sizeof(XBOX_360_CONFIGURATION_DESCRIPTOR); + memcpy_P(descriptorBuffer, &XBOX360ConfigurationDescriptor, size); + } + else if (consoleType == OG_XBOX) + { + size = sizeof(OG_XBOX_CONFIGURATION_DESCRIPTOR); + memcpy_P(descriptorBuffer, &OGXBOXConfigurationDescriptor, size); + } + else if (consoleType == ARCADE) + { + size = sizeof(GH_ARCADE_CONFIGURATION_DESCRIPTOR); + memcpy_P(descriptorBuffer, &GHArcadeConfigurationDescriptor, size); + } + else + { + size = sizeof(UNIVERSAL_CONFIGURATION_DESCRIPTOR); + memcpy_P(descriptorBuffer, &UniversalConfigurationDescriptor, size); + UNIVERSAL_CONFIGURATION_DESCRIPTOR *desc = (UNIVERSAL_CONFIGURATION_DESCRIPTOR *)descriptorBuffer; - if (consoleType == PS4) { - desc->HIDDescriptor.wDescriptorLength = sizeof(ps4_descriptor); - desc->EndpointOutHID.wMaxPacketSize = 64; - desc->EndpointInHID.wMaxPacketSize = 64; - } else if (consoleType == IOS_FESTIVAL) { - desc->HIDDescriptor.wDescriptorLength = sizeof(ps3_descriptor); - desc->EndpointOutHID.wMaxPacketSize = 64; - desc->EndpointInHID.wMaxPacketSize = 64; + if (consoleType == PS4) + { + desc->HIDDescriptor.wDescriptorLength = sizeof(ps4_descriptor); + desc->EndpointOutHID.wMaxPacketSize = 64; + desc->EndpointInHID.wMaxPacketSize = 64; + } + else if (consoleType == PS5) + { + desc->HIDDescriptor.wDescriptorLength = sizeof(ps5_descriptor); + desc->EndpointOutHID.wMaxPacketSize = 64; + desc->EndpointInHID.wMaxPacketSize = 64; + desc->HIDDescriptor.bcdHID = 0x0111; + } + else if (consoleType == IOS_FESTIVAL) + { + desc->HIDDescriptor.wDescriptorLength = sizeof(ps3_descriptor); + desc->EndpointOutHID.wMaxPacketSize = 64; + desc->EndpointInHID.wMaxPacketSize = 64; #if DEVICE_TYPE_IS_INSTRUMENT #if defined(TICK_NKRO) || defined(TICK_SIXKRO) - } else if (consoleType == KEYBOARD_MOUSE) { - desc->HIDDescriptor.wDescriptorLength = sizeof(keyboard_mouse_descriptor); + } + else if (consoleType == KEYBOARD_MOUSE) + { + desc->HIDDescriptor.wDescriptorLength = sizeof(keyboard_mouse_descriptor); #endif #if DEVICE_TYPE == ROCK_BAND_GUITAR || DEVICE_TYPE == GUITAR_HERO_GUITAR - } else if (consoleType == FNF) { - desc->HIDDescriptor.wDescriptorLength = sizeof(fnf_descriptor); + } + else if (consoleType == FNF) + { + desc->HIDDescriptor.wDescriptorLength = sizeof(fnf_descriptor); #endif - } else { - desc->HIDDescriptor.wDescriptorLength = sizeof(ps3_instrument_descriptor); - } + } + else + { + desc->HIDDescriptor.wDescriptorLength = sizeof(ps3_instrument_descriptor); + } #else - } else if (consoleType == PS3) { - desc->HIDDescriptor.wDescriptorLength = sizeof(ps3_descriptor); - desc->EndpointOutHID.wMaxPacketSize = 64; - desc->EndpointInHID.wMaxPacketSize = 64; - } else { - desc->HIDDescriptor.wDescriptorLength = sizeof(ps3_instrument_descriptor); - } + } + else if (consoleType == PS3) + { + desc->HIDDescriptor.wDescriptorLength = sizeof(ps3_descriptor); + desc->EndpointOutHID.wMaxPacketSize = 64; + desc->EndpointInHID.wMaxPacketSize = 64; + } + else + { + desc->HIDDescriptor.wDescriptorLength = sizeof(ps3_instrument_descriptor); + } #endif - if (consoleType == UNIVERSAL) { - desc->HIDDescriptor.wDescriptorLength = sizeof(pc_descriptor); - } else { - // Strip out all the extra interfaces used for configuring / x360 compat, consoles dont need them - desc->Config.bNumInterfaces = 1; - desc->Config.wTotalLength = sizeof(HID_CONFIGURATION_DESCRIPTOR); - } + if (consoleType == UNIVERSAL) + { + desc->HIDDescriptor.wDescriptorLength = sizeof(pc_descriptor); + } + else + { + // Strip out all the extra interfaces used for configuring / x360 compat, consoles dont need them + desc->Config.bNumInterfaces = 1; + desc->Config.wTotalLength = sizeof(HID_CONFIGURATION_DESCRIPTOR); } + } #endif - break; + break; + } + case HID_DESCRIPTOR_HID: + { + size = sizeof(UNIVERSAL_CONFIGURATION_DESCRIPTOR); + memcpy_P(descriptorBuffer, &UniversalConfigurationDescriptor, size); + USB_HID_DESCRIPTOR *desc = (USB_HID_DESCRIPTOR *)descriptorBuffer; + + if (consoleType == PS4) + { + desc->wDescriptorLength = sizeof(ps4_descriptor); + } + else if (consoleType == PS5) + { + desc->wDescriptorLength = sizeof(ps5_descriptor); + desc->bcdHID = 0x0111; } - case HID_DESCRIPTOR_REPORT: { - const void *address; - seen_hid_descriptor_read = true; + else if (consoleType == IOS_FESTIVAL) + { + desc->wDescriptorLength = sizeof(ps3_descriptor); +#if DEVICE_TYPE_IS_INSTRUMENT +#if defined(TICK_NKRO) || defined(TICK_SIXKRO) + } + else if (consoleType == KEYBOARD_MOUSE) + { + desc->wDescriptorLength = sizeof(keyboard_mouse_descriptor); +#endif +#if DEVICE_TYPE == ROCK_BAND_GUITAR || DEVICE_TYPE == GUITAR_HERO_GUITAR + } + else if (consoleType == FNF) + { + desc->wDescriptorLength = sizeof(fnf_descriptor); +#endif + } + else + { + desc->wDescriptorLength = sizeof(ps3_instrument_descriptor); + } +#else + } + else if (consoleType == PS3) + { + desc->wDescriptorLength = sizeof(ps3_descriptor); + } + else + { + desc->wDescriptorLength = sizeof(ps3_instrument_descriptor); + } +#endif + if (consoleType == UNIVERSAL) + { + desc->wDescriptorLength = sizeof(pc_descriptor); + } + break; + } + case HID_DESCRIPTOR_REPORT: + { + const void *address; + seen_hid_descriptor_read = true; #if DEVICE_TYPE_IS_KEYBOARD - address = keyboard_mouse_descriptor; - size = sizeof(keyboard_mouse_descriptor); + address = keyboard_mouse_descriptor; + size = sizeof(keyboard_mouse_descriptor); #elif DEVICE_TYPE_IS_GAMEPAD - - if (consoleType == PS4) { - address = ps4_descriptor; - size = sizeof(ps4_descriptor); - } else if (consoleType == IOS_FESTIVAL) { - address = ps3_descriptor; - size = sizeof(ps3_descriptor); + if (consoleType == ARCADE) + { + address = gha_descriptor; + size = sizeof(gha_descriptor); + } + else if (consoleType == PS4) + { + address = ps4_descriptor; + size = sizeof(ps4_descriptor); + } + else if (consoleType == PS5) + { + address = ps5_descriptor; + size = sizeof(ps5_descriptor); + } + else if (consoleType == IOS_FESTIVAL) + { + address = ps3_descriptor; + size = sizeof(ps3_descriptor); #if DEVICE_TYPE == ROCK_BAND_GUITAR || DEVICE_TYPE == GUITAR_HERO_GUITAR - } else if (consoleType == FNF) { - address = fnf_descriptor; - size = sizeof(fnf_descriptor); + } + else if (consoleType == FNF) + { + address = fnf_descriptor; + size = sizeof(fnf_descriptor); #endif #if defined(TICK_NKRO) || defined(TICK_SIXKRO) - } else if (consoleType == KEYBOARD_MOUSE) { - address = keyboard_mouse_descriptor; - size = sizeof(keyboard_mouse_descriptor); + } + else if (consoleType == KEYBOARD_MOUSE) + { + address = keyboard_mouse_descriptor; + size = sizeof(keyboard_mouse_descriptor); #endif - } else if (consoleType != UNIVERSAL) { + } + else if (consoleType != UNIVERSAL) + { #if DEVICE_TYPE_IS_INSTRUMENT + address = ps3_instrument_descriptor; + size = sizeof(ps3_instrument_descriptor); +#else + if (consoleType == PS3) + { + address = ps3_descriptor; + size = sizeof(ps3_descriptor); + } + else + { address = ps3_instrument_descriptor; size = sizeof(ps3_instrument_descriptor); -#else - if (consoleType == PS3) { - address = ps3_descriptor; - size = sizeof(ps3_descriptor); - } else { - address = ps3_instrument_descriptor; - size = sizeof(ps3_instrument_descriptor); - } -#endif - } else { - address = pc_descriptor; - size = sizeof(pc_descriptor); } +#endif + } + else + { + address = pc_descriptor; + size = sizeof(pc_descriptor); + } #else - address = ps3_instrument_descriptor; - size = sizeof(ps3_instrument_descriptor); + address = ps3_instrument_descriptor; + size = sizeof(ps3_instrument_descriptor); #endif - memcpy_P(descriptorBuffer, address, size); - break; + memcpy_P(descriptorBuffer, address, size); + break; + } + case USB_DESCRIPTOR_STRING: + { + // We only care for actual string reads, not the language id + if (descriptorNumber != 0) + { + read_any_device_string = true; } - case USB_DESCRIPTOR_STRING: { - read_any_string = true; - const uint8_t *str; - if (descriptorNumber == 4) { - str = (uint8_t *)&xboxString; - } else if (descriptorNumber < 4) { - str = (uint8_t *)pgm_read_pointer(descriptorStrings + descriptorNumber); - } else if (descriptorNumber == 0xEE) { - str = (uint8_t *)&OSDescriptorString; - } else { - break; - } - size = pgm_read_byte(str + offsetof(STRING_DESCRIPTOR, bLength)); - memcpy_P(descriptorBuffer, str, size); + const uint8_t *str; + if (descriptorNumber == 5) + { + str = (uint8_t *)&rtStringInput; + } + else if (descriptorNumber == 6) + { + str = (uint8_t *)&rtStringLED; + } + else if (descriptorNumber == 4) + { + str = (uint8_t *)&xboxString; + } + else if (descriptorNumber < 4) + { + str = (uint8_t *)descriptorStrings[descriptorNumber]; + } + else if (descriptorNumber == 0xEE) + { + str = (uint8_t *)&OSDescriptorString; + seen_os_descriptor_read = true; + } + else + { break; } + size = pgm_read_byte(str + offsetof(STRING_DESCRIPTOR, bLength)); + memcpy_P(descriptorBuffer, str, size); + break; + } } return size; } diff --git a/src/shared/usb/string_descriptors.c b/src/shared/usb/string_descriptors.c index 08d2c5b9e..d14276451 100644 --- a/src/shared/usb/string_descriptors.c +++ b/src/shared/usb/string_descriptors.c @@ -32,5 +32,10 @@ const PROGMEM STRING_DESCRIPTOR productString = USB_DESCRIPTOR_STRING_UTF("Santr */ const PROGMEM STRING_DESCRIPTOR xboxString = USB_DESCRIPTOR_STRING_UTF("Xbox Security Method 3, Version 1.00, \xa9 2005 Microsoft Corporation. All rights reserved."); + +const PROGMEM STRING_DESCRIPTOR rtString = USB_DESCRIPTOR_STRING_UTF("RT GH CONTROLLER "); +const PROGMEM STRING_DESCRIPTOR rtStringLED = USB_DESCRIPTOR_STRING_UTF("RT-GH LED "); +const PROGMEM STRING_DESCRIPTOR rtStringInput = USB_DESCRIPTOR_STRING_UTF("RT-GH INPUT "); + const PROGMEM STRING_DESCRIPTOR *const descriptorStrings[3] = { &languageString, &manufacturerString, &productString}; \ No newline at end of file diff --git a/src/shared/usb/xbox.c b/src/shared/usb/xbox.c index 48c0cf9f2..5f381125f 100644 --- a/src/shared/usb/xbox.c +++ b/src/shared/usb/xbox.c @@ -25,7 +25,7 @@ const XInputInputCapabilities_t PROGMEM XInputInputCapabilities = { leftThumbY : XBOX_360_MUSTANG_PID, #elif DEVICE_TYPE == ROCK_BAND_PRO_GUITAR_SQUIRE leftThumbX : HARMONIX_VID, - leftThumbY : XBOX_360_SQUIRE_PID, + leftThumbY : XBOX_360_SQUIRE_MPA_PID, #else leftThumbX : ARDWIINO_VID, leftThumbY : ARDWIINO_PID, diff --git a/src/shared/usb/xsm3/xsm3.c b/src/shared/usb/xsm3/xsm3.c index a2934496e..277c1deb5 100644 --- a/src/shared/usb/xsm3/xsm3.c +++ b/src/shared/usb/xsm3/xsm3.c @@ -18,7 +18,7 @@ */ #include "xsm3.h" - +#include "Arduino.h" #include #include #include @@ -38,16 +38,6 @@ #define XSM3_printf #endif // XSM3_NO_DEBUGGING -#ifdef KV_KEY_ARRAY -#ifdef CONFIGURABLE_BLOBS -static const uint8_t* kv_keys = (const uint8_t*)&KV_KEY_ARRAY; -uint8_t key_count = KV_KEY_SIZE; -#else -static const PROGMEM uint8_t kv_keys[] = KV_KEY_ARRAY; -uint8_t key_count = KV_KEY_SIZE; -#endif -#endif - // constant variables uint8_t xsm3_id_data_ms_controller[0x1D] = { 0x49, 0x4B, 0x00, 0x00, 0x17, 0x41, 0x41, 0x41, @@ -55,7 +45,7 @@ uint8_t xsm3_id_data_ms_controller[0x1D] = { 0x00, 0x00, 0x80, 0x02, 0x09, 0x12, 0x82, 0x28, 0x03, 0x00, 0x01, 0x01, 0x71}; -// constant variables (not exposed outside of this module) +// static global keys from the keyvault (shared across every retail system) static const uint8_t xsm3_key_0x1D[0x10] = { 0xE3, 0x5B, 0xFB, 0x1C, 0xCD, 0xAD, 0x32, 0x5B, 0xF7, 0x0E, 0x07, 0xFD, 0x62, 0x3D, 0xA7, 0xC4}; @@ -63,6 +53,15 @@ static const uint8_t xsm3_key_0x1E[0x10] = { 0x8F, 0x29, 0x08, 0x38, 0x0B, 0x5B, 0xFE, 0x68, 0x7C, 0x26, 0x46, 0x2A, 0x51, 0xF2, 0xBC, 0x19}; +// retail keys for generating 0x23/0x24 keys from console ID +static const uint8_t xsm3_root_key_0x23[0x10] = { + 0x82, 0x80, 0x78, 0x68, 0x3A, 0x52, 0x3A, 0x98, + 0x10, 0xF4, 0x0C, 0x12, 0x70, 0x66, 0xDC, 0xBA}; + +static const uint8_t xsm3_root_key_0x24[0x10] = { + 0x66, 0x62, 0x1A, 0x78, 0xF8, 0x60, 0x9C, 0x8A, + 0x26, 0x9A, 0x04, 0xAE, 0xD8, 0x5C, 0x1E, 0xC8}; + // response to give to the given challenge command uint8_t xsm3_challenge_response[0x30]; // console id fetched from challenge init packet @@ -116,8 +115,8 @@ static uint8_t xsm3_calculate_checksum(const uint8_t* packet) { } void xsm3_set_vid_pid(const uint8_t serial[0x0C], uint16_t vid, uint16_t pid) { - memcpy(xsm3_id_data_ms_controller + 6, serial, 0x0C); + xsm3_id_data_ms_controller[6] = micros(); uint8_t* id_data = xsm3_id_data_ms_controller; // skip over the packet header id_data += 0x5; @@ -160,12 +159,14 @@ void xsm3_set_identification_data(const uint8_t id_data[0x1D]) { memcpy(xsm3_identification_data + 0x16, id_data + 0x14, sizeof(unsigned short)); } -void xsm3_import_kv_keys(const uint8_t key1[0x10], const uint8_t key2[0x10]) { - // copy the provided keys into our buffers - memcpy(xsm3_kv_2des_key_1, key1, sizeof(xsm3_kv_2des_key_1)); - memcpy(xsm3_kv_2des_key_2, key2, sizeof(xsm3_kv_2des_key_2)); +void xsm3_generate_kv_keys(const uint8_t console_id[0x8]) { + // make a sha-1 hash of the console id + uint8_t console_id_hash[0x14]; + ExCryptSha(console_id, 0x8, NULL, 0, NULL, 0, console_id_hash, 0x14); + // encrypt it with the root keys for 1st party controllers + UsbdSecXSM3AuthenticationCrypt(xsm3_root_key_0x23, console_id_hash, 0x10, xsm3_kv_2des_key_1, 1); + UsbdSecXSM3AuthenticationCrypt(xsm3_root_key_0x24, console_id_hash + 0x4, 0x10, xsm3_kv_2des_key_2, 1); } - void xsm3_do_challenge_init(uint8_t challenge_packet[0x22]) { uint8_t incoming_packet_mac[0x8]; uint8_t response_packet_mac[0x8]; @@ -188,17 +189,7 @@ void xsm3_do_challenge_init(uint8_t challenge_packet[0x22]) { if (memcmp(incoming_packet_mac + 4, challenge_packet + 0x5 + 0x18, 0x4) != 0) { XSM3_printf("[ MAC failed when validating challenge init! ]\n"); } -#ifdef KV_KEY_ARRAY - for (int i = 0; i < key_count; i++) { - uint8_t* keys = kv_keys + (i * (sizeof(xsm3_kv_2des_key_1) + sizeof(xsm3_kv_2des_key_2) + 5)); - if (memcmp(keys, xsm3_console_id, 5) == 0) { - memcpy(xsm3_kv_2des_key_1, keys + 5, sizeof(xsm3_kv_2des_key_1)); - memcpy(xsm3_kv_2des_key_2, keys + 5 + sizeof(xsm3_kv_2des_key_1), sizeof(xsm3_kv_2des_key_2)); - break; - } - } -#endif - // TODO: somehow..derive the kv keys from the console certificate + xsm3_generate_kv_keys(xsm3_console_id); // the random value is swapped at an 8 byte boundary memcpy(xsm3_random_console_data_swap, xsm3_random_console_data + 0x8, 0x8); diff --git a/src/shared/usb/xsm3/xsm3.h b/src/shared/usb/xsm3/xsm3.h index 9a78a3484..b4b0f6e90 100644 --- a/src/shared/usb/xsm3/xsm3.h +++ b/src/shared/usb/xsm3/xsm3.h @@ -41,9 +41,6 @@ void xsm3_initialise_state(); // Sets the identification data to use. void xsm3_set_identification_data(const uint8_t id_data[0x1D]); -// Imports the console-specific keys (GetKey index 0x23 and 0x24 for wired controllers) into the current state. -void xsm3_import_kv_keys(const uint8_t key1[0x10], const uint8_t key2[0x10]); - // Initialises the XSM3 state using information from the challenge init packet (0x82) and places a response in xsm3_challenge_response. void xsm3_do_challenge_init(uint8_t challenge_packet[0x22]);