Skip to content

Commit 3083b47

Browse files
v3.10.1
- Bluepad32 v3.10.1 - Updated BTstack - Keyboard support - Updated sketch / Controller.ino
1 parent a907fc4 commit 3083b47

File tree

3 files changed

+485
-210
lines changed

3 files changed

+485
-210
lines changed
Lines changed: 216 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,252 @@
11
#include <Bluepad32.h>
22

3-
GamepadPtr myGamepads[BP32_MAX_GAMEPADS];
3+
ControllerPtr myControllers[BP32_MAX_GAMEPADS];
44

55
// This callback gets called any time a new gamepad is connected.
66
// Up to 4 gamepads can be connected at the same time.
7-
void onConnectedGamepad(GamepadPtr gp) {
8-
bool foundEmptySlot = false;
9-
for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
10-
if (myGamepads[i] == nullptr) {
11-
Serial.printf("CALLBACK: Gamepad is connected, index=%d\n", i);
12-
// Additionally, you can get certain gamepad properties like:
13-
// Model, VID, PID, BTAddr, flags, etc.
14-
GamepadProperties properties = gp->getProperties();
15-
Serial.printf("Gamepad model: %s, VID=0x%04x, PID=0x%04x\n",
16-
gp->getModelName().c_str(), properties.vendor_id,
17-
properties.product_id);
18-
myGamepads[i] = gp;
19-
foundEmptySlot = true;
20-
break;
7+
void onConnectedController(ControllerPtr ctl) {
8+
bool foundEmptySlot = false;
9+
for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
10+
if (myControllers[i] == nullptr) {
11+
Serial.printf("CALLBACK: Controller is connected, index=%d\n", i);
12+
// Additionally, you can get certain gamepad properties like:
13+
// Model, VID, PID, BTAddr, flags, etc.
14+
ControllerProperties properties = ctl->getProperties();
15+
Serial.printf("Controller model: %s, VID=0x%04x, PID=0x%04x\n", ctl->getModelName().c_str(), properties.vendor_id,
16+
properties.product_id);
17+
myControllers[i] = ctl;
18+
foundEmptySlot = true;
19+
break;
20+
}
21+
}
22+
if (!foundEmptySlot) {
23+
Serial.println("CALLBACK: Controller connected, but could not found empty slot");
2124
}
22-
}
23-
if (!foundEmptySlot) {
24-
Serial.println(
25-
"CALLBACK: Gamepad connected, but could not found empty slot");
26-
}
2725
}
2826

29-
void onDisconnectedGamepad(GamepadPtr gp) {
30-
bool foundGamepad = false;
27+
void onDisconnectedController(ControllerPtr ctl) {
28+
bool foundController = false;
3129

32-
for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
33-
if (myGamepads[i] == gp) {
34-
Serial.printf("CALLBACK: Gamepad is disconnected from index=%d\n", i);
35-
myGamepads[i] = nullptr;
36-
foundGamepad = true;
37-
break;
30+
for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
31+
if (myControllers[i] == ctl) {
32+
Serial.printf("CALLBACK: Controller disconnected from index=%d\n", i);
33+
myControllers[i] = nullptr;
34+
foundController = true;
35+
break;
36+
}
3837
}
39-
}
4038

41-
if (!foundGamepad) {
42-
Serial.println(
43-
"CALLBACK: Gamepad disconnected, but not found in myGamepads");
44-
}
39+
if (!foundController) {
40+
Serial.println("CALLBACK: Controller disconnected, but not found in myControllers");
41+
}
4542
}
4643

47-
// Arduino setup function. Runs in CPU 1
48-
void setup() {
49-
Serial.begin(115200);
50-
Serial.printf("Firmware: %s\n", BP32.firmwareVersion());
51-
const uint8_t *addr = BP32.localBdAddress();
52-
Serial.printf("BD Addr: %2X:%2X:%2X:%2X:%2X:%2X\n", addr[0], addr[1], addr[2],
53-
addr[3], addr[4], addr[5]);
54-
55-
// Setup the Bluepad32 callbacks
56-
BP32.setup(&onConnectedGamepad, &onDisconnectedGamepad);
57-
58-
// "forgetBluetoothKeys()" should be called when the user performs
59-
// a "device factory reset", or similar.
60-
// Calling "forgetBluetoothKeys" in setup() just as an example.
61-
// Forgetting Bluetooth keys prevents "paired" gamepads to reconnect.
62-
// But might also fix some connection / re-connection issues.
63-
BP32.forgetBluetoothKeys();
44+
void dumpGamepad(ControllerPtr ctl) {
45+
Serial.printf(
46+
"idx=%d, dpad: 0x%02x, buttons: 0x%04x, axis L: %4d, %4d, axis R: %4d, %4d, brake: %4d, throttle: %4d, "
47+
"misc: 0x%02x, gyro x:%6d y:%6d z:%6d, accel x:%6d y:%6d z:%6d\n",
48+
ctl->index(), // Controller Index
49+
ctl->dpad(), // DPAD
50+
ctl->buttons(), // bitmask of pressed buttons
51+
ctl->axisX(), // (-511 - 512) left X Axis
52+
ctl->axisY(), // (-511 - 512) left Y axis
53+
ctl->axisRX(), // (-511 - 512) right X axis
54+
ctl->axisRY(), // (-511 - 512) right Y axis
55+
ctl->brake(), // (0 - 1023): brake button
56+
ctl->throttle(), // (0 - 1023): throttle (AKA gas) button
57+
ctl->miscButtons(), // bitmak of pressed "misc" buttons
58+
ctl->gyroX(), // Gyro X
59+
ctl->gyroY(), // Gyro Y
60+
ctl->gyroZ(), // Gyro Z
61+
ctl->accelX(), // Accelerometer X
62+
ctl->accelY(), // Accelerometer Y
63+
ctl->accelZ() // Accelerometer Z
64+
);
6465
}
6566

66-
// Arduino loop function. Runs in CPU 1
67-
void loop() {
68-
// This call fetches all the gamepad info from the NINA (ESP32) module.
69-
// Just call this function in your main loop.
70-
// The gamepads pointer (the ones received in the callbacks) gets updated
71-
// automatically.
72-
BP32.update();
73-
74-
// It is safe to always do this before using the gamepad API.
75-
// This guarantees that the gamepad is valid and connected.
76-
for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
77-
GamepadPtr myGamepad = myGamepads[i];
78-
79-
if (myGamepad && myGamepad->isConnected()) {
80-
// There are different ways to query whether a button is pressed.
81-
// By query each button individually:
82-
// a(), b(), x(), y(), l1(), etc...
83-
if (myGamepad->a()) {
67+
void dumpMouse(ControllerPtr ctl) {
68+
Serial.printf("idx=%d, buttons: 0x%04x, scrollWheel=0x%04x, delta X: %4d, delta Y: %4d\n",
69+
ctl->index(), // Controller Index
70+
ctl->buttons(), // bitmask of pressed buttons
71+
ctl->scrollWheel(), // Scroll Wheel
72+
ctl->deltaX(), // (-511 - 512) left X Axis
73+
ctl->deltaY() // (-511 - 512) left Y axis
74+
);
75+
}
76+
77+
void dumpKeyboard(ControllerPtr ctl) {
78+
// TODO: Print pressed keys
79+
Serial.printf("idx=%d\n", ctl->index());
80+
}
81+
82+
void dumpBalanceBoard(ControllerPtr ctl) {
83+
Serial.printf("idx=%d, TL=%u, TR=%u, BL=%u, BR=%u, temperature=%d\n",
84+
ctl->index(), // Controller Index
85+
ctl->topLeft(), // top-left scale
86+
ctl->topRight(), // top-right scale
87+
ctl->bottomLeft(), // bottom-left scale
88+
ctl->bottomRight(), // bottom-right scale
89+
ctl->temperature() // temperature: used to adjust the scale value's precision
90+
);
91+
}
92+
93+
void processGamepad(ControllerPtr ctl) {
94+
// There are different ways to query whether a button is pressed.
95+
// By query each button individually:
96+
// a(), b(), x(), y(), l1(), etc...
97+
if (ctl->a()) {
8498
static int colorIdx = 0;
8599
// Some gamepads like DS4 and DualSense support changing the color LED.
86100
// It is possible to change it by calling:
87101
switch (colorIdx % 3) {
88-
case 0:
89-
// Red
90-
myGamepad->setColorLED(255, 0, 0);
91-
break;
92-
case 1:
93-
// Green
94-
myGamepad->setColorLED(0, 255, 0);
95-
break;
96-
case 2:
97-
// Blue
98-
myGamepad->setColorLED(0, 0, 255);
99-
break;
102+
case 0:
103+
// Red
104+
ctl->setColorLED(255, 0, 0);
105+
break;
106+
case 1:
107+
// Green
108+
ctl->setColorLED(0, 255, 0);
109+
break;
110+
case 2:
111+
// Blue
112+
ctl->setColorLED(0, 0, 255);
113+
break;
100114
}
101115
colorIdx++;
102-
}
116+
}
103117

104-
if (myGamepad->b()) {
118+
if (ctl->b()) {
105119
// Turn on the 4 LED. Each bit represents one LED.
106120
static int led = 0;
107121
led++;
108122
// Some gamepads like the DS3, DualSense, Nintendo Wii, Nintendo Switch
109-
// support changing the "Player LEDs": those 4 LEDs that usually
110-
// indicate the "gamepad seat". It is possible to change them by
111-
// calling:
112-
myGamepad->setPlayerLEDs(led & 0x0f);
113-
}
123+
// support changing the "Player LEDs": those 4 LEDs that usually indicate
124+
// the "gamepad seat".
125+
// It is possible to change them by calling:
126+
ctl->setPlayerLEDs(led & 0x0f);
127+
}
114128

115-
if (myGamepad->x()) {
129+
if (ctl->x()) {
116130
// Duration: 255 is ~2 seconds
117131
// force: intensity
118132
// Some gamepads like DS3, DS4, DualSense, Switch, Xbox One S support
119133
// rumble.
120134
// It is possible to set it by calling:
121-
myGamepad->setRumble(0xc0 /* force */, 0xc0 /* duration */);
122-
}
123-
124-
// Another way to query the buttons, is by calling buttons(), or
125-
// miscButtons() which return a bitmask.
126-
// Some gamepads also have DPAD, axis and more.
127-
Serial.printf(
128-
"idx=%d, dpad: 0x%02x, buttons: 0x%04x, axis L: %4d, %4d, axis R: "
129-
"%4d, %4d, brake: %4d, throttle: %4d, misc: 0x%02x, gyro x:%6d y:%6d "
130-
"z:%6d, accel x:%6d y:%6d z:%6d\n",
131-
i, // Gamepad Index
132-
myGamepad->dpad(), // DPAD
133-
myGamepad->buttons(), // bitmask of pressed buttons
134-
myGamepad->axisX(), // (-511 - 512) left X Axis
135-
myGamepad->axisY(), // (-511 - 512) left Y axis
136-
myGamepad->axisRX(), // (-511 - 512) right X axis
137-
myGamepad->axisRY(), // (-511 - 512) right Y axis
138-
myGamepad->brake(), // (0 - 1023): brake button
139-
myGamepad->throttle(), // (0 - 1023): throttle (AKA gas) button
140-
myGamepad->miscButtons(), // bitmak of pressed "misc" buttons
141-
myGamepad->gyroX(), // Gyro X
142-
myGamepad->gyroY(), // Gyro Y
143-
myGamepad->gyroZ(), // Gyro Z
144-
myGamepad->accelX(), // Accelerometer X
145-
myGamepad->accelY(), // Accelerometer Y
146-
myGamepad->accelZ() // Accelerometer Z
147-
);
148-
149-
// You can query the axis and other properties as well. See Gamepad.h
150-
// For all the available functions.
135+
ctl->setRumble(0xc0 /* force */, 0xc0 /* duration */);
151136
}
152-
}
153137

154-
// The main loop must have some kind of "yield to lower priority task" event.
155-
// Otherwise the watchdog will get triggered.
156-
// If your main loop doesn't have one, just add a simple `vTaskDelay(1)`.
157-
// Detailed info here:
158-
// https://stackoverflow.com/questions/66278271/task-watchdog-got-triggered-the-tasks-did-not-reset-the-watchdog-in-time
138+
// Another way to query controller data is by getting the buttons() function.
139+
// See how the different "dump*" functions dump the Controller info.
140+
dumpGamepad(ctl);
141+
}
142+
143+
void processMouse(ControllerPtr ctl) {
144+
// This is just an example.
145+
if (ctl->scrollWheel() > 0) {
146+
// Do Something
147+
} else if (ctl->scrollWheel() < 0) {
148+
// Do something else
149+
}
150+
151+
// See "dumpMouse" for possible things to query.
152+
dumpMouse(ctl);
153+
}
159154

160-
// vTaskDelay(1);
161-
delay(150);
155+
void processKeyboard(ControllerPtr ctl) {
156+
// This is just an example.
157+
if (ctl->isKeyPressed(Keyboard_A)) {
158+
// Do Something
159+
Serial.println("Key 'A' pressed");
160+
}
161+
162+
// Don't do "else" here.
163+
// Multiple keys can be pressed at the same time.
164+
if (ctl->isKeyPressed(Keyboard_LeftShift)) {
165+
// Do something else
166+
Serial.println("Key 'LEFT SHIFT' pressed");
167+
}
168+
169+
// Don't do "else" here.
170+
// Multiple keys can be pressed at the same time.
171+
if (ctl->isKeyPressed(Keyboard_LeftArrow)) {
172+
// Do something else
173+
Serial.println("Key 'Left Arrow' pressed");
174+
}
175+
176+
// See "dumpKeyboard" for possible things to query.
177+
dumpKeyboard(ctl);
178+
}
179+
180+
void processBalanceBoard(ControllerPtr ctl) {
181+
// This is just an example.
182+
if (ctl->topLeft() > 10000) {
183+
// Do Something
184+
}
185+
186+
// See "dumpBalanceBoard" for possible things to query.
187+
dumpBalanceBoard(ctl);
188+
}
189+
190+
// Arduino setup function. Runs in CPU 1
191+
void setup() {
192+
Serial.begin(115200);
193+
Serial.printf("Firmware: %s\n", BP32.firmwareVersion());
194+
const uint8_t* addr = BP32.localBdAddress();
195+
Serial.printf("BD Addr: %2X:%2X:%2X:%2X:%2X:%2X\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
196+
197+
// Setup the Bluepad32 callbacks
198+
BP32.setup(&onConnectedController, &onDisconnectedController);
199+
200+
// "forgetBluetoothKeys()" should be called when the user performs
201+
// a "device factory reset", or similar.
202+
// Calling "forgetBluetoothKeys" in setup() just as an example.
203+
// Forgetting Bluetooth keys prevents "paired" gamepads to reconnect.
204+
// But might also fix some connection / re-connection issues.
205+
BP32.forgetBluetoothKeys();
206+
207+
// Enables mouse / touchpad support for gamepads that support them.
208+
// When enabled controllers like DualSense and DualShock4 generate two connected devices:
209+
// - First one: the gamepad
210+
// - Second one, which is a "vritual device", is a mouse
211+
// By default it is disabled.
212+
BP32.enableVirtualDevice(false);
213+
}
214+
215+
// Arduino loop function. Runs in CPU 1
216+
void loop() {
217+
// This call fetches all the gamepad info from the NINA (ESP32) module.
218+
// Just call this function in your main loop.
219+
// The gamepads pointer (the ones received in the callbacks) gets updated
220+
// automatically.
221+
BP32.update();
222+
223+
// It is safe to always do this before using the gamepad API.
224+
// This guarantees that the gamepad is valid and connected.
225+
for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
226+
ControllerPtr myController = myControllers[i];
227+
228+
if (myController && myController->isConnected()) {
229+
if (myController->isGamepad()) {
230+
processGamepad(myController);
231+
} else if (myController->isMouse()) {
232+
processMouse(myController);
233+
} else if (myController->isKeyboard()) {
234+
processKeyboard(myController);
235+
} else if (myController->isBalanceBoard()) {
236+
processBalanceBoard(myController);
237+
} else {
238+
Serial.printf("Data not available yet\n");
239+
continue;
240+
}
241+
// See ArduinoController.h for all the available functions.
242+
}
243+
}
244+
// The main loop must have some kind of "yield to lower priority task" event.
245+
// Otherwise the watchdog will get triggered.
246+
// If your main loop doesn't have one, just add a simple `vTaskDelay(1)`.
247+
// Detailed info here:
248+
// https://stackoverflow.com/questions/66278271/task-watchdog-got-triggered-the-tasks-did-not-reset-the-watchdog-in-time
249+
250+
// vTaskDelay(1);
251+
delay(150);
162252
}

0 commit comments

Comments
 (0)