Skip to content

Commit a907fc4

Browse files
v3.9.0 changes
- Update boards.txt from ESP32 Arduino Core 2.0.14 and remove S2 based boards. - Update platform.txt from Arduino Core 2.0.14 (with Bluepad32 includes) - Platform define version 4.4.5 (and not 4.4.5-hash) - Add WebAppBLEService example fixes: ricardoquesada/bluepad32#37
1 parent 01aef77 commit a907fc4

File tree

10 files changed

+2936
-66
lines changed

10 files changed

+2936
-66
lines changed

bluepad32_files/boards.txt

Lines changed: 2337 additions & 53 deletions
Large diffs are not rendered by default.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# BluePad32 ESP OTA Update example
2+
3+
**This is a copy of https://github.com/ste2425/BluePad32OTAExample**
4+
5+
This is an example Application which performs OTA Updates on the ESP32 whilst BluePad32 can connect to controllers.
6+
7+
It is purly a proof of concept but proves the functionality works.
8+
9+
It can be used in conjunction with a correspondsing web app.
10+
11+
The source for the web app is [here](https://github.com/ste2425/OTAWebapp) and a version of the web app is hosted [here](https://ste2425.github.io/OTAWebapp/).
12+
13+
Simply flash the ESP. This is an extension of the template provided by BluePad32 [here](https://gitlab.com/ricardoquesada/esp-idf-arduino-bluepad32-template) with OTA functionality applied on top.
14+
15+
The BLE code is an extension of the delayed response example (with the delayed parts removed) privided by BTStack, it can be viewed [here](https://github.com/bluekitchen/btstack/blob/master/example/att_delayed_response.c).
16+
17+
# NOTES
18+
19+
`BLE_setup` must be called after `BP32.setup`.
20+
* `BP32.enableNewBluetoothConnections` must be set to false when doing the OTA update (in this demo it is hard coded to false, more info below)
21+
* With the ESP menuconfig the following config was set `CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192`. With the default stack size when the OTA had been uploaded and was applied with `esp_ota_end(otaHandler)` a stack overflow exception was encountered.
22+
23+
## `BP32.enableNewBluetoothConnections` issue explained
24+
25+
If an OTA is uploaded (or any large amounts of data streamed to the ESP) whilst `BP32.enableNewBluetoothConnections` is set to true it causes slow downs in the upload and eventual disconnects between the ESP and the web browser. This is most likely bandwidth issues (admitedly i do not know). What ever the reason the advise is to set this to false when streaming large amounts of data and enable again (if needed) once finished. Small adhoc BLE communication is fine whilst this is set to true. Its only streaming large data like a binary for OTA updates.
26+
27+
## Generating a binary to update
28+
29+
The easiest option is to modify the variable `test_string` in `ble.cpp` and compile. Then copy the binary from the build folder and give it to the UI. In the UI when the `read` button is clicked `test_string` is the value the characteristic returns. So change this allows you to do a before and after and prove the OTA worked.
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/****************************************************************************
2+
http://retro.moe/unijoysticle2
3+
4+
Copyright 2021 Ricardo Quesada
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
****************************************************************************/
18+
19+
#include "sdkconfig.h"
20+
#ifndef CONFIG_BLUEPAD32_PLATFORM_ARDUINO
21+
#error "Must only be compiled when using Bluepad32 Arduino platform"
22+
#endif // !CONFIG_BLUEPAD32_PLATFORM_ARDUINO
23+
24+
#include <Arduino.h>
25+
#include <Bluepad32.h>
26+
#include "ble_server.h"
27+
28+
//
29+
// README FIRST, README FIRST, README FIRST
30+
//
31+
// Bluepad32 has a built-in interactive console.
32+
// By default it is enabled (hey, this is a great feature!).
33+
// But it is incompatible with Arduino "Serial" class.
34+
//
35+
// Instead of using "Serial" you can use Bluepad32 "Console" class instead.
36+
// It is somewhat similar to Serial but not exactly the same.
37+
//
38+
// Should you want to still use "Serial", you have to disable the Bluepad32's console
39+
// from "sdkconfig.defaults" with:
40+
// CONFIG_BLUEPAD32_USB_CONSOLE_ENABLE=n
41+
42+
GamepadPtr myGamepads[BP32_MAX_GAMEPADS];
43+
44+
// This callback gets called any time a new gamepad is connected.
45+
// Up to 4 gamepads can be connected at the same time.
46+
void onConnectedGamepad(GamepadPtr gp)
47+
{
48+
bool foundEmptySlot = false;
49+
for (int i = 0; i < BP32_MAX_GAMEPADS; i++)
50+
{
51+
if (myGamepads[i] == nullptr)
52+
{
53+
Console.printf("CALLBACK: Gamepad is connected, index=%d\n", i);
54+
// Additionally, you can get certain gamepad properties like:
55+
// Model, VID, PID, BTAddr, flags, etc.
56+
GamepadProperties properties = gp->getProperties();
57+
Console.printf("Gamepad model: %s, VID=0x%04x, PID=0x%04x\n", gp->getModelName(), properties.vendor_id,
58+
properties.product_id);
59+
myGamepads[i] = gp;
60+
foundEmptySlot = true;
61+
break;
62+
}
63+
}
64+
if (!foundEmptySlot)
65+
{
66+
Console.println("CALLBACK: Gamepad connected, but could not found empty slot");
67+
}
68+
}
69+
70+
void onDisconnectedGamepad(GamepadPtr gp)
71+
{
72+
bool foundGamepad = false;
73+
74+
for (int i = 0; i < BP32_MAX_GAMEPADS; i++)
75+
{
76+
if (myGamepads[i] == gp)
77+
{
78+
Console.printf("CALLBACK: Gamepad is disconnected from index=%d\n", i);
79+
myGamepads[i] = nullptr;
80+
foundGamepad = true;
81+
break;
82+
}
83+
}
84+
85+
if (!foundGamepad)
86+
{
87+
Console.println("CALLBACK: Gamepad disconnected, but not found in myGamepads");
88+
}
89+
}
90+
91+
// Arduino setup function. Runs in CPU 1
92+
void setup()
93+
{
94+
Console.printf("Firmware: %s\n", BP32.firmwareVersion());
95+
const uint8_t *addr = BP32.localBdAddress();
96+
Console.printf("BD Addr: %2X:%2X:%2X:%2X:%2X:%2X\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
97+
98+
// Setup the Bluepad32 callbacks
99+
BP32.setup(&onConnectedGamepad, &onDisconnectedGamepad);
100+
101+
// "forgetBluetoothKeys()" should be called when the user performs
102+
// a "device factory reset", or similar.
103+
// Calling "forgetBluetoothKeys" in setup() just as an example.
104+
// Forgetting Bluetooth keys prevents "paired" gamepads to reconnect.
105+
// But might also fix some connection / re-connection issues.
106+
BP32.forgetBluetoothKeys();
107+
108+
BP32.enableNewBluetoothConnections(false);
109+
110+
BLE_SERVER_SETUP();
111+
}
112+
113+
// Arduino loop function. Runs in CPU 1
114+
void loop()
115+
{
116+
// This call fetches all the gamepad info from the NINA (ESP32) module.
117+
// Just call this function in your main loop.
118+
// The gamepads pointer (the ones received in the callbacks) gets updated
119+
// automatically.
120+
BP32.update();
121+
122+
// It is safe to always do this before using the gamepad API.
123+
// This guarantees that the gamepad is valid and connected.
124+
for (int i = 0; i < BP32_MAX_GAMEPADS; i++)
125+
{
126+
GamepadPtr myGamepad = myGamepads[i];
127+
128+
if (myGamepad && myGamepad->isConnected())
129+
{
130+
// There are different ways to query whether a button is pressed.
131+
// By query each button individually:
132+
// a(), b(), x(), y(), l1(), etc...
133+
if (myGamepad->a())
134+
{
135+
static int colorIdx = 0;
136+
// Some gamepads like DS4 and DualSense support changing the color LED.
137+
// It is possible to change it by calling:
138+
switch (colorIdx % 3)
139+
{
140+
case 0:
141+
// Red
142+
myGamepad->setColorLED(255, 0, 0);
143+
break;
144+
case 1:
145+
// Green
146+
myGamepad->setColorLED(0, 255, 0);
147+
break;
148+
case 2:
149+
// Blue
150+
myGamepad->setColorLED(0, 0, 255);
151+
break;
152+
}
153+
colorIdx++;
154+
}
155+
156+
if (myGamepad->b())
157+
{
158+
// Turn on the 4 LED. Each bit represents one LED.
159+
static int led = 0;
160+
led++;
161+
// Some gamepads like the DS3, DualSense, Nintendo Wii, Nintendo Switch
162+
// support changing the "Player LEDs": those 4 LEDs that usually indicate
163+
// the "gamepad seat".
164+
// It is possible to change them by calling:
165+
myGamepad->setPlayerLEDs(led & 0x0f);
166+
}
167+
168+
if (myGamepad->x())
169+
{
170+
// Duration: 255 is ~2 seconds
171+
// force: intensity
172+
// Some gamepads like DS3, DS4, DualSense, Switch, Xbox One S support
173+
// rumble.
174+
// It is possible to set it by calling:
175+
myGamepad->setRumble(0xc0 /* force */, 0xc0 /* duration */);
176+
}
177+
178+
// Another way to query the buttons, is by calling buttons(), or
179+
// miscButtons() which return a bitmask.
180+
// Some gamepads also have DPAD, axis and more.
181+
Console.printf(
182+
"idx=%d, dpad: 0x%02x, buttons: 0x%04x, axis L: %4d, %4d, axis R: %4d, %4d, brake: %4d, throttle: %4d, "
183+
"misc: 0x%02x, gyro x:%6d y:%6d z:%6d, accel x:%6d y:%6d z:%6d\n",
184+
i, // Gamepad Index
185+
myGamepad->dpad(), // DPAD
186+
myGamepad->buttons(), // bitmask of pressed buttons
187+
myGamepad->axisX(), // (-511 - 512) left X Axis
188+
myGamepad->axisY(), // (-511 - 512) left Y axis
189+
myGamepad->axisRX(), // (-511 - 512) right X axis
190+
myGamepad->axisRY(), // (-511 - 512) right Y axis
191+
myGamepad->brake(), // (0 - 1023): brake button
192+
myGamepad->throttle(), // (0 - 1023): throttle (AKA gas) button
193+
myGamepad->miscButtons(), // bitmak of pressed "misc" buttons
194+
myGamepad->gyroX(), // Gyro X
195+
myGamepad->gyroY(), // Gyro Y
196+
myGamepad->gyroZ(), // Gyro Z
197+
myGamepad->accelX(), // Accelerometer X
198+
myGamepad->accelY(), // Accelerometer Y
199+
myGamepad->accelZ() // Accelerometer Z
200+
);
201+
202+
// You can query the axis and other properties as well. See ArduinoController.h
203+
// For all the available functions.
204+
}
205+
}
206+
// The main loop must have some kind of "yield to lower priority task" event.
207+
// Otherwise the watchdog will get triggered.
208+
// If your main loop doesn't have one, just add a simple `vTaskDelay(1)`.
209+
// Detailed info here:
210+
// https://stackoverflow.com/questions/66278271/task-watchdog-got-triggered-the-tasks-did-not-reset-the-watchdog-in-time
211+
212+
// vTaskDelay(1);
213+
delay(150);
214+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
PRIMARY_SERVICE, GAP_SERVICE
2+
CHARACTERISTIC, GAP_DEVICE_NAME, READ, "Delayed Response"
3+
4+
PRIMARY_SERVICE, GATT_SERVICE
5+
CHARACTERISTIC, GATT_DATABASE_HASH, READ,
6+
7+
// Some Service
8+
PRIMARY_SERVICE, 0000FF10-0000-1000-8000-00805F9B34FB
9+
// Some Characteristic, with read and write
10+
CHARACTERISTIC, 0000FF11-0000-1000-8000-00805F9B34FB, READ | WRITE | DYNAMIC,
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
2+
// ./main/att_delayed_response.h generated from ./main/att_delayed_response.gatt for BTstack
3+
// it needs to be regenerated when the .gatt file is updated.
4+
5+
// To generate ./main/att_delayed_response.h:
6+
// C:\Espressif\frameworks\esp-idf-v4.4/components/btstack/tool/compile_gatt.py ./main/att_delayed_response.gatt ./main/att_delayed_response.h
7+
8+
// att db format version 1
9+
10+
// binary attribute representation:
11+
// - size in bytes (16), flags(16), handle (16), uuid (16/128), value(...)
12+
13+
#include <stdint.h>
14+
15+
// Reference: https://en.cppreference.com/w/cpp/feature_test
16+
#if __cplusplus >= 200704L
17+
constexpr
18+
#endif
19+
const uint8_t profile_data[] =
20+
{
21+
// ATT DB Version
22+
1,
23+
24+
// 0x0001 PRIMARY_SERVICE-GAP_SERVICE
25+
0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x18,
26+
// 0x0002 CHARACTERISTIC-GAP_DEVICE_NAME - READ
27+
0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x02, 0x03, 0x00, 0x00, 0x2a,
28+
// 0x0003 VALUE CHARACTERISTIC-GAP_DEVICE_NAME - READ -'Delayed Response'
29+
// READ_ANYBODY
30+
0x18, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x2a, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x20, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
31+
// 0x0004 PRIMARY_SERVICE-GATT_SERVICE
32+
0x0a, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x28, 0x01, 0x18,
33+
// 0x0005 CHARACTERISTIC-GATT_DATABASE_HASH - READ
34+
0x0d, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x28, 0x02, 0x06, 0x00, 0x2a, 0x2b,
35+
// 0x0006 VALUE CHARACTERISTIC-GATT_DATABASE_HASH - READ -''
36+
// READ_ANYBODY
37+
0x18, 0x00, 0x02, 0x00, 0x06, 0x00, 0x2a, 0x2b, 0xa4, 0x20, 0xa3, 0x54, 0x52, 0x70, 0xc5, 0x3f, 0xfa, 0x40, 0xba, 0xd0, 0xfd, 0x1b, 0xd5, 0xc2,
38+
// Some Service
39+
// 0x0007 PRIMARY_SERVICE-0000FF10-0000-1000-8000-00805F9B34FB
40+
0x18, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x28, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x10, 0xff, 0x00, 0x00,
41+
// Some Characteristic, with read and write
42+
// 0x0008 CHARACTERISTIC-0000FF11-0000-1000-8000-00805F9B34FB - READ | WRITE | DYNAMIC
43+
0x1b, 0x00, 0x02, 0x00, 0x08, 0x00, 0x03, 0x28, 0x0a, 0x09, 0x00, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x11, 0xff, 0x00, 0x00,
44+
// 0x0009 VALUE CHARACTERISTIC-0000FF11-0000-1000-8000-00805F9B34FB - READ | WRITE | DYNAMIC
45+
// READ_ANYBODY, WRITE_ANYBODY
46+
0x16, 0x00, 0x0a, 0x03, 0x09, 0x00, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x11, 0xff, 0x00, 0x00,
47+
// END
48+
0x00, 0x00,
49+
}; // total size 99 bytes
50+
51+
52+
//
53+
// list service handle ranges
54+
//
55+
#define ATT_SERVICE_GAP_SERVICE_START_HANDLE 0x0001
56+
#define ATT_SERVICE_GAP_SERVICE_END_HANDLE 0x0003
57+
#define ATT_SERVICE_GAP_SERVICE_01_START_HANDLE 0x0001
58+
#define ATT_SERVICE_GAP_SERVICE_01_END_HANDLE 0x0003
59+
#define ATT_SERVICE_GATT_SERVICE_START_HANDLE 0x0004
60+
#define ATT_SERVICE_GATT_SERVICE_END_HANDLE 0x0006
61+
#define ATT_SERVICE_GATT_SERVICE_01_START_HANDLE 0x0004
62+
#define ATT_SERVICE_GATT_SERVICE_01_END_HANDLE 0x0006
63+
#define ATT_SERVICE_0000FF10_0000_1000_8000_00805F9B34FB_START_HANDLE 0x0007
64+
#define ATT_SERVICE_0000FF10_0000_1000_8000_00805F9B34FB_END_HANDLE 0x0009
65+
#define ATT_SERVICE_0000FF10_0000_1000_8000_00805F9B34FB_01_START_HANDLE 0x0007
66+
#define ATT_SERVICE_0000FF10_0000_1000_8000_00805F9B34FB_01_END_HANDLE 0x0009
67+
68+
//
69+
// list mapping between characteristics and handles
70+
//
71+
#define ATT_CHARACTERISTIC_GAP_DEVICE_NAME_01_VALUE_HANDLE 0x0003
72+
#define ATT_CHARACTERISTIC_GATT_DATABASE_HASH_01_VALUE_HANDLE 0x0006
73+
#define ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE 0x0009

0 commit comments

Comments
 (0)