diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 29 | ||||
-rw-r--r-- | src/btstack_config.h | 81 | ||||
-rw-r--r-- | src/gamepad.c | 266 | ||||
-rw-r--r-- | src/gamepad.h | 20 | ||||
-rw-r--r-- | src/main.c | 30 | ||||
-rw-r--r-- | src/tusb_config.h | 127 | ||||
-rw-r--r-- | src/xinput.c | 96 |
7 files changed, 649 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..4782941 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,29 @@ +add_subdirectory(${PROJECT_SOURCE_DIR}/deps/tusb_xinput xinput_host) + +add_executable(btinput + main.c + xinput.c + gamepad.c + tusb_config.h + btstack_config.h +) + +target_include_directories(btinput PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_enable_stdio_usb(btinput 0) +pico_enable_stdio_uart(btinput 1) + +pico_add_extra_outputs(btinput) + +target_link_libraries(btinput PUBLIC + pico_stdlib + pico_cyw43_arch_none + pico_btstack_cyw43 + pico_btstack_classic + tinyusb_host + tinyusb_board + xinput_host +) + diff --git a/src/btstack_config.h b/src/btstack_config.h new file mode 100644 index 0000000..e38468b --- /dev/null +++ b/src/btstack_config.h @@ -0,0 +1,81 @@ +#ifndef _PICO_BTSTACK_BTSTACK_CONFIG_H +#define _PICO_BTSTACK_BTSTACK_CONFIG_H + +// BTstack features that can be enabled +#ifdef ENABLE_BLE +#warning no BLE +#undef ENABLE_BLE +#endif +#define ENABLE_LOG_DEBUG +#define ENABLE_LOG_INFO +#define ENABLE_LOG_ERROR +#define ENABLE_PRINTF_HEXDUMP +#define ENABLE_SCO_OVER_HCI +#define ENABLE_CLASSIC_OOB_PAIRING +#define ENABLE_LOG_BTSTACK_EVENTS + +// BTstack configuration. buffers, sizes, ... +#define HCI_OUTGOING_PRE_BUFFER_SIZE 16 +#define HCI_ACL_PAYLOAD_SIZE (1691 + 4) +#define HCI_ACL_CHUNK_SIZE_ALIGNMENT 4 +#define MAX_NR_AVDTP_CONNECTIONS 1 +#define MAX_NR_AVDTP_STREAM_ENDPOINTS 1 +#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 1 +#define MAX_NR_HID_HOST_CONNECTIONS 1 +#define MAX_NR_HIDS_CLIENTS 1 +#define MAX_NR_HFP_CONNECTIONS 1 +#define MAX_NR_L2CAP_CHANNELS 4 +#define MAX_NR_L2CAP_SERVICES 3 +#define MAX_NR_RFCOMM_CHANNELS 1 +#define MAX_NR_RFCOMM_MULTIPLEXERS 1 +#define MAX_NR_RFCOMM_SERVICES 1 +#define MAX_NR_SERVICE_RECORD_ITEMS 4 +#define MAX_NR_SM_LOOKUP_ENTRIES 3 +#define MAX_NR_WHITELIST_ENTRIES 16 +#define MAX_NR_LE_DEVICE_DB_ENTRIES 16 + +// Limit number of ACL/SCO Buffer to use by stack to avoid cyw43 shared bus overrun +#define MAX_NR_CONTROLLER_ACL_BUFFERS 3 +#define MAX_NR_CONTROLLER_SCO_PACKETS 3 + +// Enable and configure HCI Controller to Host Flow Control to avoid cyw43 shared bus overrun +#define ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL +#define HCI_HOST_ACL_PACKET_LEN 1024 +#define HCI_HOST_ACL_PACKET_NUM 3 +#define HCI_HOST_SCO_PACKET_LEN 120 +#define HCI_HOST_SCO_PACKET_NUM 3 + +// Link Key DB and LE Device DB using TLV on top of Flash Sector interface +#define NVM_NUM_DEVICE_DB_ENTRIES 16 +#define NVM_NUM_LINK_KEYS 16 + +// We don't give btstack a malloc, so use a fixed-size ATT DB. +#define MAX_ATT_DB_SIZE 512 + +// BTstack HAL configuration +#define HAVE_EMBEDDED_TIME_MS + +// map btstack_assert onto Pico SDK assert() +#define HAVE_ASSERT + +// Some USB dongles take longer to respond to HCI reset (e.g. BCM20702A). +#define HCI_RESET_RESEND_TIMEOUT_MS 1000 + +#define ENABLE_SOFTWARE_AES128 +#define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS + +#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 + +#ifdef ENABLE_CLASSIC +#define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE +#endif + +#endif // _PICO_BTSTACK_BTSTACK_CONFIG_H diff --git a/src/gamepad.c b/src/gamepad.c new file mode 100644 index 0000000..93af18f --- /dev/null +++ b/src/gamepad.c @@ -0,0 +1,266 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include "btstack.h" +#include "gamepad.h" +#include "hardware/gpio.h" +#include "classic/rfcomm.h" + +#define BUTTON_PIN 13 + +static const char hid_device_name[] = "Wirecutter Adapter"; +static const char service_name[] = "Wireless Gamepad"; +static uint8_t hid_service_buffer[4090]; +static uint8_t device_id_sdp_service_buffer[100]; +static btstack_packet_callback_registration_t hci_event_callback_registration; +uint16_t hid_cid; + +const uint16_t host_max_latency = 1600; +const uint16_t host_min_timeout = 3200; + +const uint8_t hid_descriptor_gamepad[] = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x05, // USAGE (Joystick - 0x04; Gamepad - 0x05; Multi-axis Controller - 0x08) + 0xa1, 0x01, // COLLECTION (Application) + // Buttons + 0x85, 0x03, // REPORT_ID (Default: 3) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x10, // USAGE_MAXIMUM (Up to 128 buttons possible) + 0x95, 0x10, // REPORT_COUNT (# of buttons) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + // Axis + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Pointer) + 0x16, 0x01, 0x80, // LOGICAL_MINIMUM (-32767) + 0x26, 0xFF, 0x7F, // LOGICAL_MAXIMUM (+32767) + 0x75, 0x10, // REPORT_SIZE (16) + 0x95, 0x04, // REPORT_COUNT (configuration.getAxisCount()) + 0xA1, 0x00, // COLLECTION (Physical) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x09, 0x32, // USAGE (Z) + 0x09, 0x35, // USAGE (Rz) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION (Physical) + + // Simulation + 0x05, 0x02, // USAGE_PAGE (Simulation Controls) + 0x16, 0x00, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0xA1, 0x00, // COLLECTION (Physical) + 0x09, 0xC4, // USAGE (Accelerator) + 0x09, 0xC5, // USAGE (Brake) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION (Physical) + + // HAT + 0xA1, 0x00, // COLLECTION (Physical) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x39, // USAGE (Hat Switch) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x08, // Logical Max (8) + 0x35, 0x00, // Physical Min (0) + 0x46, 0x3B, 0x01, // Physical Max (315) + 0x65, 0x12, // Unit (SI Rot : Ang Pos) + 0x75, 0x08, // Report Size (8) + 0x95, 1, // Report Count (4) + 0x81, 0x42, // Input (Data, Variable, Absolute) + 0xc0, // END_COLLECTION (Physical) + 0xc0, // END_COLLECTION (Physical) +}; + +gamepad_t gamepad; + +void request_can_send_now_event(void) +{ + hid_device_request_can_send_now_event(hid_cid); +} + +static void send_report_joystick(){ + uint8_t report[] = { + 0xa1, 0x03, + (gamepad.buttons), (gamepad.buttons >> 8), + (gamepad.x), (gamepad.x >> 8), + (gamepad.y), (gamepad.y >> 8), + (gamepad.z), (gamepad.z >> 8), + (gamepad.rz), (gamepad.rz >> 8), + gamepad.gas, gamepad.brake, + gamepad.hat, + }; + hid_device_send_interrupt_message(hid_cid, &report[0], sizeof(report)); +} + +static bd_addr_t local_addr; +static bd_addr_t event_addr; +static uint16_t rfcomm_channel_id; +static uint8_t rfcomm_channel_nr; +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t packet_size){ + UNUSED(channel); + UNUSED(packet_size); + uint8_t status; + + + switch(packet_type) + { + case HCI_EVENT_PACKET: + switch (hci_event_packet_get_type(packet)) + { + case BTSTACK_EVENT_STATE: + if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; + gap_local_bd_addr(local_addr); + printf("BTstack up and running on %s.\n", bd_addr_to_str(local_addr)); + break; + case GAP_EVENT_DEDICATED_BONDING_COMPLETED: + printf("GAP Dedicated Bonding Complete, status 0x%02x\n", packet[2]); + break; + case HCI_EVENT_PIN_CODE_REQUEST: + printf("Pin code request - using '0000'\n"); + hci_event_pin_code_request_get_bd_addr(packet, event_addr); + gap_pin_code_response(event_addr, "0000"); + break; + case HCI_EVENT_USER_CONFIRMATION_REQUEST: + // ssp: inform about user confirmation request + printf("SSP User Confirmation Request with numeric value '%06"PRIu32"'\n", hci_event_user_confirmation_request_get_numeric_value(packet)); + printf("SSP User Confirmation Auto accept\n"); + break; + case RFCOMM_EVENT_INCOMING_CONNECTION: + rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr); + rfcomm_channel_nr = rfcomm_event_incoming_connection_get_server_channel(packet); + rfcomm_channel_id = rfcomm_event_incoming_connection_get_rfcomm_cid(packet); + printf("RFCOMM channel %u requested for %s\n", rfcomm_channel_nr, bd_addr_to_str(event_addr)); + rfcomm_decline_connection(rfcomm_channel_id); + break; + case HCI_EVENT_HID_META: + switch (hci_event_hid_meta_get_subevent_code(packet)){ + case HID_SUBEVENT_CONNECTION_OPENED: + status = hid_subevent_connection_opened_get_status(packet); + if (status != ERROR_CODE_SUCCESS) { + // outgoing connection failed + printf("Connection failed, status 0x%x\n", status); + hid_cid = 0; + return; + } + hid_cid = hid_subevent_connection_opened_get_hid_cid(packet); + printf("HID Connected\n"); + hid_device_request_can_send_now_event(hid_cid); + gap_discoverable_control(0); + break; + case HID_SUBEVENT_CONNECTION_CLOSED: + printf("HID Disconnected\n"); + hid_cid = 0; + break; + case HID_SUBEVENT_CAN_SEND_NOW: + if(hid_cid!=0){ //Solves crash when disconnecting gamepad on android + send_report_joystick(); + hid_device_request_can_send_now_event(hid_cid); + } + break; + default: + break; + } + break; + default: + break; + } + break; + default: + break; + } +} + +static void sync_irq_handler(void) +{ + if (gpio_get_irq_event_mask(BUTTON_PIN) & GPIO_IRQ_EDGE_FALL) + { + gpio_acknowledge_irq(BUTTON_PIN, GPIO_IRQ_EDGE_FALL); + hid_device_disconnect(hid_cid); + gap_discoverable_control(1); + printf("Set discoverable\n"); + } +} + +static void setup_sync_button(void) +{ + gpio_init(BUTTON_PIN); + gpio_set_dir(BUTTON_PIN, GPIO_IN); + gpio_pull_up(BUTTON_PIN); + + gpio_set_irq_enabled(BUTTON_PIN, GPIO_IRQ_EDGE_FALL, true); + gpio_add_raw_irq_handler(BUTTON_PIN, &sync_irq_handler); + irq_set_enabled(IO_IRQ_BANK0, true); +} + +int btstack_main(int argc, const char * argv[]); +int btstack_main(int argc, const char * argv[]){ + (void)argc; + (void)argv; + + gap_discoverable_control(0); + gap_set_class_of_device(0x2508); + gap_set_local_name(hid_device_name); +#ifdef ENABLE_BLE + gap_set_connection_parameters(0x0060, 0x0030, 0x06, 0x06, 0, 0x0048, 2, 0x0030); +#endif + + // L2CAP + l2cap_init(); + // SDP Server + sdp_init(); + memset(hid_service_buffer, 0, sizeof(hid_service_buffer)); + + uint8_t hid_virtual_cable = 0; + uint8_t hid_remote_wake = 1; + uint8_t hid_reconnect_initiate = 1; + uint8_t hid_normally_connectable = 1; + + hid_sdp_record_t hid_params = { + 0x2508, + 0, + 0, + 1, // remote wake + 0, + 1, // normally connectable + 0, // boot device + host_max_latency, host_min_timeout, + 3200, + hid_descriptor_gamepad, + sizeof(hid_descriptor_gamepad), + hid_device_name + }; + + hid_create_sdp_record( + hid_service_buffer, + 0x10000, + &hid_params + ); + + hid_create_sdp_record(hid_service_buffer, sdp_create_service_record_handle(), &hid_params); + btstack_assert(de_get_len( hid_service_buffer) <= sizeof(hid_service_buffer)); + sdp_register_service(hid_service_buffer); + + // HID Device + hid_device_init(0, sizeof(hid_descriptor_gamepad), hid_descriptor_gamepad); + + hci_event_callback_registration.callback = &packet_handler; + hci_add_event_handler(&hci_event_callback_registration); + + hid_device_register_packet_handler(&packet_handler); + + // turn on! + hci_power_control(HCI_POWER_ON); + + setup_sync_button(); + + return 0; +} +/* LISTING_END */ +/* EXAMPLE_END */
\ No newline at end of file diff --git a/src/gamepad.h b/src/gamepad.h new file mode 100644 index 0000000..295619c --- /dev/null +++ b/src/gamepad.h @@ -0,0 +1,20 @@ +#ifndef GAMEPAD_H +#define GAMEPAD_H + +typedef struct +{ + int16_t x; + int16_t y; + int16_t z; + int16_t rz; + uint8_t gas; + uint8_t brake; + uint8_t hat; + uint16_t buttons; +} gamepad_t; + +extern gamepad_t gamepad; + +void request_can_send_now_event(void); + +#endif
\ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..be8e598 --- /dev/null +++ b/src/main.c @@ -0,0 +1,30 @@ +#include <stdio.h> +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" + +#include "bsp/board_api.h" +#include "tusb.h" + +const uint LED_PIN = 25; + +int btstack_main(int argc, const char * argv[]); + +int main() +{ + if (cyw43_arch_init()) { + printf("failed to initialise cyw43_arch\n"); + return -1; + } + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + + board_init(); + tuh_init(BOARD_TUH_RHPORT); + btstack_main(0, NULL); + + printf("Init done\n"); + + while(1) + { + tuh_task(); + } +} diff --git a/src/tusb_config.h b/src/tusb_config.h new file mode 100644 index 0000000..9363194 --- /dev/null +++ b/src/tusb_config.h @@ -0,0 +1,127 @@ +/* + * 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. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Board Specific Configuration +//--------------------------------------------------------------------+ + +#if CFG_TUSB_MCU == OPT_MCU_RP2040 +// change to 1 if using pico-pio-usb as host controller for raspberry rp2040 +#define CFG_TUH_RPI_PIO_USB 0 +#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB +#endif + +// RHPort number used for host can be defined by board.mk, default to port 0 +#ifndef BOARD_TUH_RHPORT +#define BOARD_TUH_RHPORT 0 +#endif + +// RHPort max operational speed can defined by board.mk +#ifndef BOARD_TUH_MAX_SPEED +#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by compiler flags for flexibility +#ifndef CFG_TUSB_MCU +#error CFG_TUSB_MCU must be defined +#endif + +#ifndef CFG_TUSB_OS +#define CFG_TUSB_OS OPT_OS_NONE +#endif + +#ifndef CFG_TUSB_DEBUG +#define CFG_TUSB_DEBUG 3 +#endif + +// Enable Host stack +#define CFG_TUH_ENABLED 1 + +// Default is max speed that hardware controller could support with on-chip PHY +#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +//-------------------------------------------------------------------- +// CONFIGURATION +//-------------------------------------------------------------------- + +// Size of buffer to hold descriptors and other data used for enumeration +#define CFG_TUH_ENUMERATION_BUFSIZE 512 + +#define CFG_TUH_HUB 0 // number of supported hubs +#define CFG_TUH_CDC 0 +#define CFG_TUH_HID 0 // typical keyboard + mouse device can have 3-4 HID interfaces +#define CFG_TUH_MSC 0 +#define CFG_TUH_VENDOR 0 +#define CFG_TUH_XINPUT 1 + +// max device support (excluding hub device) +#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports + +//------------- HID -------------// +#define CFG_TUH_HID_EPIN_BUFSIZE 64 +#define CFG_TUH_HID_EPOUT_BUFSIZE 64 + +//------------- CDC -------------// + +// Set Line Control state on enumeration/mounted: +// DTR ( bit 0), RTS (bit 1) +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 + +// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t +// bit rate = 115200, 1 stop bit, no parity, 8 bit data width +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } + + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/src/xinput.c b/src/xinput.c new file mode 100644 index 0000000..07eb01a --- /dev/null +++ b/src/xinput.c @@ -0,0 +1,96 @@ +#include "tusb.h" +#include "xinput_host.h" +#include "gamepad.h" + +#define XINPUT_GAMEPAD_SHOULDER (XINPUT_GAMEPAD_LEFT_SHOULDER | XINPUT_GAMEPAD_RIGHT_SHOULDER) +#define XINPUT_GAMEPAD_DPAD (XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_RIGHT) +#define XINPUT_GAMEPAD_THUMB (XINPUT_GAMEPAD_LEFT_THUMB | XINPUT_GAMEPAD_RIGHT_THUMB) + + +//Since https://github.com/hathach/tinyusb/pull/2222, we can add in custom vendor drivers easily +usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count){ + *driver_count = 1; + return &usbh_xinput_driver; +} + +void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* xid_itf, uint16_t len) +{ + const xinput_gamepad_t *p = &xid_itf->pad; + + if (xid_itf->last_xfer_result == XFER_RESULT_SUCCESS) + { + if (xid_itf->connected && xid_itf->new_pad_data) + { + gamepad.x = p->sThumbLX; + gamepad.y = p->sThumbLY; + gamepad.z = p->sThumbRX; + gamepad.rz = p->sThumbRY; + //gamepad.rx = ((float)p->bLeftTrigger * 256) - 32767; + //gamepad.ry = ((float)p->bRightTrigger * 256) - 32767; + gamepad.gas = p->bRightTrigger; + gamepad.brake = p->bLeftTrigger; + + uint8_t dpad = (p->wButtons & XINPUT_GAMEPAD_DPAD); + + if (dpad & XINPUT_GAMEPAD_DPAD_UP) + { + if (dpad & XINPUT_GAMEPAD_DPAD_LEFT) + gamepad.hat = 8; + else if (dpad & XINPUT_GAMEPAD_DPAD_RIGHT) + gamepad.hat = 2; + else + gamepad.hat = 1; + } + else if (dpad & XINPUT_GAMEPAD_DPAD_DOWN) + { + if (dpad & XINPUT_GAMEPAD_DPAD_LEFT) + gamepad.hat = 6; + else if (dpad & XINPUT_GAMEPAD_DPAD_RIGHT) + gamepad.hat = 4; + else + gamepad.hat = 5; + } + else if (dpad & XINPUT_GAMEPAD_DPAD_LEFT) + gamepad.hat = 7; + else if (dpad & XINPUT_GAMEPAD_DPAD_RIGHT) + gamepad.hat = 3; + else + gamepad.hat = 0; + + gamepad.buttons = \ + (p->wButtons & (XINPUT_GAMEPAD_A | XINPUT_GAMEPAD_B)) >> 12 | + (p->wButtons & (XINPUT_GAMEPAD_X | XINPUT_GAMEPAD_Y)) >> 11 | + (p->wButtons & XINPUT_GAMEPAD_SHOULDER) >> 2 | + (p->wButtons & XINPUT_GAMEPAD_BACK) << 5 | + (p->wButtons & XINPUT_GAMEPAD_START) << 7 | + (p->wButtons & XINPUT_GAMEPAD_THUMB) << 7 | + (p->wButtons & XINPUT_GAMEPAD_GUIDE) << 2 | + 0; + + request_can_send_now_event(); + } + } + tuh_xinput_receive_report(dev_addr, instance); +} + +void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const xinputh_interface_t *xinput_itf) +{ + TU_LOG1("Controller attached\n"); + // If this is a Xbox 360 Wireless controller we need to wait for a connection packet + // on the in pipe before setting LEDs etc. So just start getting data until a controller is connected. + if (xinput_itf->type == XBOX360_WIRELESS && xinput_itf->connected == false) + { + tuh_xinput_receive_report(dev_addr, instance); + return; + } + tuh_xinput_set_led(dev_addr, instance, 0, true); + tuh_xinput_set_led(dev_addr, instance, 1, true); + tuh_xinput_set_rumble(dev_addr, instance, 0, 0, true); + tuh_xinput_receive_report(dev_addr, instance); +} + +void tuh_xinput_umount_cb(uint8_t dev_addr, uint8_t instance) +{ + TU_LOG1("Controller removed, clearing controls\n"); + memset(&gamepad, sizeof(gamepad), 0); +}
\ No newline at end of file |