ricardoquesada / bluepad32

Bluetooth gamepad, mouse and keyboard support for ESP32 and PicoW
https://bluepad32.readthedocs.io/
Other
503 stars 53 forks source link

[Bug]: More than three Xboxone handles will cause problems #91

Open yythackery opened 3 months ago

yythackery commented 3 months ago

What happened?

When I am using ESP32 as my platform and simultaneously connecting the fourth Xboxone controller, the program crashes as shown below. And when connecting to the third handle, it shows that the connection is normal, but there is no data given to the callback function my_platform_on_controller_data when operating the third handle.

Bluepad32 Version

latest from develop branch

Bluepad32 version custom

Example: Using Git develop branch commit hash #xxxxxxx

Bluepad32 Platform

ESP-IDF

Platform version

ESP-IDF v5.2.1

Controller

Xbox Wireless (model 1914, 3 buttons)

Microcontroller

ESP32

Microcontroller board

ESP32-WROOM-32

OS

Windows

Relevant log output

Bluepad32 (C) 2016-2024 Ricardo Quesada and contributors.
Version: v4.0.2
BTstack: Copyright (C) 2017 BlueKitchen GmbH.
Platform: custom
custom: init()
Max connected gamepads: 4
BR/EDR support: enabled
BLE support: enabled
Device ID SDP service record size: 64
Gap security level: 2
Periodic Inquiry: max=5, min=4, len=3
I (602) BTDM_INIT: BT controller compile version [0f0c5a2]
I (612) BTDM_INIT: Bluetooth MAC: d0:ef:76:45:f9:8a
I (622) phy_init: phy_version 4791,2c4672b,Dec 20 2023,16:06:06
Bluetooth Allowlist: Disabled
I (1172) console: Command history disabled

Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.
Could not find property 12
Could not find property 11
BTstack up and running at D0:EF:76:45:F9:8A
HCI not ready, cannot send packet, will again try later. Current state idx=1
custom: on_init_complete()
BR/EDR scan -> 1
BLE scan -> 1
custom: Bluetooth enabled: 1
Deleting stored BR/EDR link keys:
.
Deleting stored BLE link keys:
44:16:22:59:04:6F - type 0
                                                                                                                                                           F4:6A:D7:8D:44:6A - type 0
.
bp32> Found, connect to device with public address F4:6A:D7:8D:44:6A ...
Creating device: F4:6A:D7:8D:44:6A (idx=0)
Device '' identified as Gamepad
BLE scan -> 0
SM_EVENT_IDENTITY_RESOLVING_STARTED
Identity resolving failed for F4:6A:D7:8D:44:6A

Using con_handle: 0
SM_EVENT_PAIRING_STARTED
Just works requested
Connection encrypted: 1
Identity created: type 0 address F4:6A:D7:8D:44:6A
Pairing complete, success
Manufacturer Name: Microsoft
Serial Number:    09BM6798617124
Firmware Revision: 5.17.3202.0
Vendor Source ID: 0x02
Vendor  ID:       0x045e
Product ID:       0x0b13
Product Version:  0x0517
Device Information service found
Search for HID service.
Using hids_cid=1
GATTSERVICE_SUBEVENT_HID_SERVICE_CONNECTED, status=0x00
HID service client connected, found 1 services, protocol_mode=1
Device detected as Xbox Wireless: 0x20
Device F4:6A:D7:8D:44:6A is connected
custom: device connected: 0x3ffc4fb8
Xbox: Assuming it is firmware v5.x
Device setup (F4:6A:D7:8D:44:6A) is complete
custom: device ready: 0x3ffc4fb8
BLE scan -> 1
Found, connect to device with public address 44:16:22:59:04:6F ...
Creating device: 44:16:22:59:04:6F (idx=1)
Device '' identified as Gamepad
BLE scan -> 0
SM_EVENT_IDENTITY_RESOLVING_STARTED
Identity resolving failed for 44:16:22:59:04:6F

Using con_handle: 0x1
SM_EVENT_PAIRING_STARTED
get data
Just works requested
Connection encrypted: 1
Identity created: type 0 address 44:16:22:59:04:6F
Pairing complete, success
Manufacturer Name: Microsoft
get data
Serial Number:    09712083764036
Firmware Revision: 5.20.7.0
Vendor Source ID: 0x02
Vendor  ID:       0x045e
Product ID:       0x0b13
Product Version:  0x0520
Device Information service found
Search for HID service.
Using hids_cid=2
GATTSERVICE_SUBEVENT_HID_SERVICE_CONNECTED, status=0x00
HID service client connected, found 1 services, protocol_mode=1
Device detected as Xbox Wireless: 0x20
Device 44:16:22:59:04:6F is connected
custom: device connected: 0x3ffc668c
Xbox: Assuming it is firmware v5.x
Device setup (44:16:22:59:04:6F) is complete
custom: device ready: 0x3ffc668c
BLE scan -> 1
get data
get data
get data
get data
get data
get data
get data
Found, connect to device with public address 44:16:22:56:7F:16 ...
Creating device: 44:16:22:56:7F:16 (idx=2)
Device '' identified as Gamepad
BLE scan -> 0
SM_EVENT_IDENTITY_RESOLVING_STARTED
Identity resolving failed for 44:16:22:56:7F:16

Using con_handle: 0x2
SM_EVENT_PAIRING_STARTED
Just works requested
Connection encrypted: 1
Identity created: type 0 address 44:16:22:56:7F:16
Pairing complete, success
Manufacturer Name: Microsoft
Serial Number:    09700273962036
Firmware Revision: 5.17.3202.0
Vendor Source ID: 0x02
Vendor  ID:       0x045e
Product ID:       0x0b13
Product Version:  0x0517
Device Information service found
Search for HID service.
Using hids_cid=3
GATTSERVICE_SUBEVENT_HID_SERVICE_CONNECTED, status=0x00
HID service client connected, found 1 services, protocol_mode=1
Device detected as Xbox Wireless: 0x20
Device 44:16:22:56:7F:16 is connected
custom: device connected: 0x3ffc7d60
Xbox: Assuming it is firmware v5.x
Device setup (44:16:22:56:7F:16) is complete
custom: device ready: 0x3ffc7d60
BLE scan -> 1
get data  (This is the connection of the third handle. After I pressed the directional key, only the first time there was data, and the rest had no data.)
Found, connect to device with public address 44:16:22:86:B8:C0 ...
Creating device: 44:16:22:86:B8:C0 (idx=3)----crush~
Device '' identified as Gamepad
BLE scan -> 0
SM_EVENT_IDENTITY_RESOLVING_STARTED
Identity resolving failed for 44:16:22:86:B8:C0

Using con_handle: 0x3
SM_EVENT_PAIRING_STARTED
Just works requested
Connection encrypted: 1
Identity created: type 0 address 44:16:22:86:B8:C0
Pairing complete, success
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x40125c46  PS      : 0x00060430  A0      : 0x80049b9c  A1      : 0x3ffdfa00
0x40125c46: r_lld_evt_update_create at ??:?

A2      : 0x07ffffff  A3      : 0x00000024  A4      : 0x00000001  A5      : 0x3ffdfa60
A6      : 0x0030bb00  A7      : 0x00000000  A8      : 0x3ffdc2f8  A9      : 0x3ffdf9e0
A10     : 0x0000dc80  A11     : 0x00000001  A12     : 0x00000000  A13     : 0x3ffafd68
A14     : 0x00000000  A15     : 0x3ffb8360  SAR     : 0x00000016  EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000008  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0x00000000
0x4000c2e0: memcpy in ROM
0x4000c2f6: memcpy in ROM

Backtrace: 0x40125c43:0x3ffdfa00 0x40049b99:0x3ffdfa60 0x400457cd:0x3ffdfa90 0x4008a402:0x3ffdfad0 0x40019d11:0x3ffdfb00 0x40055b4d:0x3ffdfb20 0x4011aa83:0x3ffdfb40 0x4011b0f6:0x3ffdfb60 0x40094435:0x3ffdfb90
0x40125c43: r_lld_evt_update_create at ??:?
0x40049b99: r_lld_con_update_req in ROM
0x400457cd: llc_con_upd_req_ind_handler in ROM
0x4008a402: ke_task_schedule at ke_task.c:?
0x40019d11: r_ke_event_schedule in ROM
0x40055b4d: r_rwip_schedule in ROM
0x4011aa83: r_rw_schedule at ??:?
0x4011b0f6: btdm_controller_task at ??:?
0x40094435: vPortTaskWrapper at D:/Espressif/frameworks/esp-idf-v5.2.1/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:134

Relevant sketch

// Example file - Public Domain
// Need help? https://tinyurl.com/bluepad32-help

#include <string.h>

#include <uni.h>

// Custom "instance"
typedef struct my_platform_instance_s {
    uni_gamepad_seat_t gamepad_seat;  // which "seat" is being used
} my_platform_instance_t;

// Declarations
static void trigger_event_on_gamepad(uni_hid_device_t* d);
static my_platform_instance_t* get_my_platform_instance(uni_hid_device_t* d);

//
// Platform Overrides
//
static void my_platform_init(int argc, const char** argv) {
    ARG_UNUSED(argc);
    ARG_UNUSED(argv);

    logi("custom: init()\n");

#if 0
    uni_gamepad_mappings_t mappings = GAMEPAD_DEFAULT_MAPPINGS;

    // Inverted axis with inverted Y in RY.
    mappings.axis_x = UNI_GAMEPAD_MAPPINGS_AXIS_RX;
    mappings.axis_y = UNI_GAMEPAD_MAPPINGS_AXIS_RY;
    mappings.axis_ry_inverted = true;
    mappings.axis_rx = UNI_GAMEPAD_MAPPINGS_AXIS_X;
    mappings.axis_ry = UNI_GAMEPAD_MAPPINGS_AXIS_Y;

    // Invert A & B
    mappings.button_a = UNI_GAMEPAD_MAPPINGS_BUTTON_B;
    mappings.button_b = UNI_GAMEPAD_MAPPINGS_BUTTON_A;

    uni_gamepad_set_mappings(&mappings);
#endif
    //    uni_bt_service_set_enabled(true);
}

static void my_platform_on_init_complete(void) {
    logi("custom: on_init_complete()\n");

    // Safe to call "unsafe" functions since they are called from BT thread

    // Start scanning
    uni_bt_enable_new_connections_unsafe(true);

    // Based on runtime condition, you can delete or list the stored BT keys.
    if (1)
        uni_bt_del_keys_unsafe();
    else
        uni_bt_list_keys_unsafe();
}

static void my_platform_on_device_connected(uni_hid_device_t* d) {
    logi("custom: device connected: %p\n", d);
}

static void my_platform_on_device_disconnected(uni_hid_device_t* d) {
    logi("custom: device disconnected: %p\n", d);
}

static uni_error_t my_platform_on_device_ready(uni_hid_device_t* d) {
    logi("custom: device ready: %p\n", d);
    my_platform_instance_t* ins = get_my_platform_instance(d);
    ins->gamepad_seat = GAMEPAD_SEAT_A;

    //trigger_event_on_gamepad(d);
    return UNI_ERROR_SUCCESS;
}

static void my_platform_on_controller_data(uni_hid_device_t* d, uni_controller_t* ctl) {
    static uint8_t leds = 0;
    static uint8_t enabled = true;
    static uni_controller_t prev = {0};
    uni_gamepad_t* gp;

    // Optimization to avoid processing the previous data so that the console
    // does not get spammed with a lot of logs, but remove it from your project.
    if (memcmp(&prev, ctl, sizeof(*ctl)) == 0) {
        return;
    }
    prev = *ctl;
    // Print device Id before dumping gamepad.
    // This could be very CPU intensive and might crash the ESP32.
    // Remove these 2 lines in production code.
    //    logi("(%p), id=%d, \n", d, uni_hid_device_get_idx_for_instance(d));
    //    uni_controller_dump(ctl);

    switch (ctl->klass) {
        case UNI_CONTROLLER_CLASS_GAMEPAD:
            logi("get data\n");
            gp = &ctl->gamepad;

            // Debugging
            // Axis ry: control rumble
            if ((gp->buttons & BUTTON_A) && d->report_parser.play_dual_rumble != NULL) {
                d->report_parser.play_dual_rumble(d, 0 /* delayed start ms */, 50 /* duration ms */,
                                                  128 /* weak magnitude */, 40 /* strong magnitude */);
            }
            // Buttons: Control LEDs On/Off
            if ((gp->buttons & BUTTON_B) && d->report_parser.set_player_leds != NULL) {
                d->report_parser.set_player_leds(d, leds++ & 0x0f);
            }
            // Axis: control RGB color
            if ((gp->buttons & BUTTON_X) && d->report_parser.set_lightbar_color != NULL) {
                uint8_t r = (gp->axis_x * 256) / 512;
                uint8_t g = (gp->axis_y * 256) / 512;
                uint8_t b = (gp->axis_rx * 256) / 512;
                d->report_parser.set_lightbar_color(d, r, g, b);
            }

            // Toggle Bluetooth connections
            if ((gp->buttons & BUTTON_SHOULDER_L) && enabled) {
                logi("*** Disabling Bluetooth connections\n");
                uni_bt_enable_new_connections_safe(false);
                enabled = false;
            }
            if ((gp->buttons & BUTTON_SHOULDER_R) && !enabled) {
                logi("*** Enabling Bluetooth connections\n");
                uni_bt_enable_new_connections_safe(true);
                enabled = true;
            }
            break;
        default:
            break;
    }
}

static const uni_property_t* my_platform_get_property(uni_property_idx_t idx) {
    ARG_UNUSED(idx);
    return NULL;
}

static void my_platform_on_oob_event(uni_platform_oob_event_t event, void* data) {
    switch (event) {
        case UNI_PLATFORM_OOB_GAMEPAD_SYSTEM_BUTTON: {
            uni_hid_device_t* d = data;

            if (d == NULL) {
                loge("ERROR: my_platform_on_oob_event: Invalid NULL device\n");
                return;
            }
            logi("custom: on_device_oob_event(): %d\n", event);

            my_platform_instance_t* ins = get_my_platform_instance(d);
            ins->gamepad_seat = ins->gamepad_seat == GAMEPAD_SEAT_A ? GAMEPAD_SEAT_B : GAMEPAD_SEAT_A;

            trigger_event_on_gamepad(d);
            break;
        }

        case UNI_PLATFORM_OOB_BLUETOOTH_ENABLED:
            logi("custom: Bluetooth enabled: %d\n", (bool)(data));
            break;

        default:
            logi("my_platform_on_oob_event: unsupported event: 0x%04x\n", event);
            break;
    }
}

//
// Helpers
//
static my_platform_instance_t* get_my_platform_instance(uni_hid_device_t* d) {
    return (my_platform_instance_t*)&d->platform_data[0];
}

static void trigger_event_on_gamepad(uni_hid_device_t* d) {
    my_platform_instance_t* ins = get_my_platform_instance(d);

    if (d->report_parser.play_dual_rumble != NULL) {
        d->report_parser.play_dual_rumble(d, 0 /* delayed start ms */, 150 /* duration ms */, 128 /* weak magnitude */,
                                          40 /* strong magnitude */);
    }

    if (d->report_parser.set_player_leds != NULL) {
        d->report_parser.set_player_leds(d, ins->gamepad_seat);
    }

    if (d->report_parser.set_lightbar_color != NULL) {
        uint8_t red = (ins->gamepad_seat & 0x01) ? 0xff : 0;
        uint8_t green = (ins->gamepad_seat & 0x02) ? 0xff : 0;
        uint8_t blue = (ins->gamepad_seat & 0x04) ? 0xff : 0;
        d->report_parser.set_lightbar_color(d, red, green, blue);
    }
}

//
// Entry Point
//
struct uni_platform* get_my_platform(void) {
    static struct uni_platform plat = {
        .name = "custom",
        .init = my_platform_init,
        .on_init_complete = my_platform_on_init_complete,
        .on_device_connected = my_platform_on_device_connected,
        .on_device_disconnected = my_platform_on_device_disconnected,
        .on_device_ready = my_platform_on_device_ready,
        .on_oob_event = my_platform_on_oob_event,
        .on_controller_data = my_platform_on_controller_data,
        .get_property = my_platform_get_property,
    };

    return &plat;
}
ricardoquesada commented 2 months ago

I can reproduce it as well.

It happens with BLE controllers. I cannot pair more than 2 BLE controllers... I don't receive data from it... or crashes.

But works Ok with non-BLE (BR/EDR) controllers.

yythackery commented 2 months ago

After my testing, it should have been due to insufficient resources in the ESP32 hardware, so I eventually replaced it with another chip.

ricardoquesada commented 2 months ago

what do you mean "insufficient resources" ? did you replace it with another esp32 chip ? which one ? is it working now?

ricardoquesada commented 2 months ago

Pico W had the same issue. Fixed here: https://github.com/ricardoquesada/bluepad32/commit/db6d69a1c42bf5f6dc2401ce002c9289a3bd4b49

yythackery commented 2 months ago

what do you mean "insufficient resources" ? did you replace it with another esp32 chip ? which one ? is it working now?

I want to choose another Bluetooth chip to implement it, but I haven't chosen it yet.

yythackery commented 2 months ago

resources

what do you mean "insufficient resources" ? did you replace it with another esp32 chip ? which one ? is it working now?

It should be tested that when connecting to the third one, the data can enter the uni_hid_device_process_controller function, but cannot enter uni_get_platform() ->on_controller_data (d,&d ->controller); This call is very strange. Then an exception is reported when connecting the fourth x1 handle. In summary, it seems that there is an issue with the Bluetooth firmware of ESP32.

ricardoquesada commented 2 months ago

I'll investigate it a bit further... but in the meantime use Pico W (latest develop branch) which works Ok with 4 BLE controllers

yythackery commented 2 months ago

I'll investigate it a bit further... but in the meantime use Pico W (latest develop branch) which works Ok with 4 BLE controllers

Ok. Tanks.

ricardoquesada commented 2 months ago

@yythackery wondering why did you close it? did you find how to connect 4 BLE devices in ESP32 ?

ricardoquesada commented 2 months ago

(I'm reopening so that we can keep with the investigation)

yythackery commented 2 months ago

@yythackery wondering why did you close it? did you find how to connect 4 BLE devices in ESP32 ?

I have chosen another chip.

ricardoquesada commented 2 months ago

@yythackery great. which one?

yythackery commented 2 months ago

@yythackery great. which one?

esp32 s2

ricardoquesada commented 2 months ago

@yythackery esp32-s2 doesn't have bluetooth. you mean esp32 s3 ? thanks.

yythackery commented 1 month ago

@yythackery esp32-s2 doesn't have bluetooth. you mean esp32 s3 ? thanks.

yes,its s3