Created
July 11, 2025 09:21
-
-
Save ste2425/97bb6de750812e836bbcac2784fff48e to your computer and use it in GitHub Desktop.
opDitto ESP32 + Bluepad32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <Bluepad32.h> | |
| ControllerPtr myControllers[BP32_MAX_GAMEPADS]; | |
| uint8_t RXX = 0; | |
| uint8_t RYY = 0; | |
| // This callback gets called any time a new gamepad is connected. | |
| // Up to 4 gamepads can be connected at the same time. | |
| void onConnectedController(ControllerPtr ctl) { | |
| bool foundEmptySlot = false; | |
| for (int i = 0; i < BP32_MAX_GAMEPADS; i++) { | |
| if (myControllers[i] == nullptr) { | |
| Serial.printf("CALLBACK: Controller is connected, index=%d\n", i); | |
| // Additionally, you can get certain gamepad properties like: | |
| // Model, VID, PID, BTAddr, flags, etc. | |
| ControllerProperties properties = ctl->getProperties(); | |
| Serial.printf("Controller model: %s, VID=0x%04x, PID=0x%04x\n", ctl->getModelName().c_str(), properties.vendor_id, | |
| properties.product_id); | |
| myControllers[i] = ctl; | |
| foundEmptySlot = true; | |
| break; | |
| } | |
| } | |
| if (!foundEmptySlot) { | |
| Serial.println("CALLBACK: Controller connected, but could not found empty slot"); | |
| } | |
| } | |
| void onDisconnectedController(ControllerPtr ctl) { | |
| bool foundController = false; | |
| for (int i = 0; i < BP32_MAX_GAMEPADS; i++) { | |
| if (myControllers[i] == ctl) { | |
| Serial.printf("CALLBACK: Controller disconnected from index=%d\n", i); | |
| myControllers[i] = nullptr; | |
| foundController = true; | |
| break; | |
| } | |
| } | |
| if (!foundController) { | |
| Serial.println("CALLBACK: Controller disconnected, but not found in myControllers"); | |
| } | |
| } | |
| void processGamepad(ControllerPtr ctl) { | |
| auto xAxis = ctl->axisRX(); | |
| auto yAxos = ctl->axisRY(); | |
| RXX = map(xAxis, -511, 512, 0, 255); | |
| RYY = map(yAxos, -511, 512, 0, 255); | |
| } | |
| void processControllers() { | |
| for (auto myController : myControllers) { | |
| if (myController && myController->isConnected() && myController->hasData()) { | |
| if (myController->isGamepad()) { | |
| processGamepad(myController); | |
| } else { | |
| Serial.println("Unsupported controller"); | |
| } | |
| } | |
| } | |
| } | |
| // Arduino setup function. Runs in CPU 1 | |
| void setup() { | |
| Serial.begin(115200); | |
| Serial2.begin(115200, SERIAL_8N1, 18, 16); | |
| Serial.printf("Firmware: %s\n", BP32.firmwareVersion()); | |
| const uint8_t* addr = BP32.localBdAddress(); | |
| Serial.printf("BD Addr: %2X:%2X:%2X:%2X:%2X:%2X\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); | |
| // Setup the Bluepad32 callbacks | |
| BP32.setup(&onConnectedController, &onDisconnectedController); | |
| // "forgetBluetoothKeys()" should be called when the user performs | |
| // a "device factory reset", or similar. | |
| // Calling "forgetBluetoothKeys" in setup() just as an example. | |
| // Forgetting Bluetooth keys prevents "paired" gamepads to reconnect. | |
| // But it might also fix some connection / re-connection issues. | |
| BP32.forgetBluetoothKeys(); | |
| // Enables mouse / touchpad support for gamepads that support them. | |
| // When enabled, controllers like DualSense and DualShock4 generate two connected devices: | |
| // - First one: the gamepad | |
| // - Second one, which is a "virtual device", is a mouse. | |
| // By default, it is disabled. | |
| BP32.enableVirtualDevice(false); | |
| } | |
| // Arduino loop function. Runs in CPU 1. | |
| void loop() { | |
| // This call fetches all the controllers' data. | |
| // Call this function in your main loop. | |
| bool dataUpdated = BP32.update(); | |
| if (dataUpdated) | |
| processControllers(); | |
| if (Serial2.available()) { | |
| char command = Serial2.read(); | |
| Serial.write(command); | |
| // read RStick command | |
| if (command == 0xB) { | |
| Serial.print("Got Request"); | |
| uint8_t buf[2]; | |
| buf[0] = RXX; | |
| buf[1] = RYY; | |
| Serial2.write(buf, 2); | |
| // simple ping command | |
| } else if (command == 0x1) { | |
| Serial2.write(0x2); | |
| } | |
| } | |
| // The main loop must have some kind of "yield to lower priority task" event. | |
| // Otherwise, the watchdog will get triggered. | |
| // If your main loop doesn't have one, just add a simple `vTaskDelay(1)`. | |
| // Detailed info here: | |
| // https://stackoverflow.com/questions/66278271/task-watchdog-got-triggered-the-tasks-did-not-reset-the-watchdog-in-time | |
| // vTaskDelay(1); | |
| delay(150); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment