aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt29
-rw-r--r--src/btstack_config.h81
-rw-r--r--src/gamepad.c266
-rw-r--r--src/gamepad.h20
-rw-r--r--src/main.c30
-rw-r--r--src/tusb_config.h127
-rw-r--r--src/xinput.c96
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