Skip to content

Commit

Permalink
Feature: Bluetooth Low Energy (BLE) support for Esp32 (#2499)
Browse files Browse the repository at this point in the history
* Initial BLE Keyboard and Gamepad libraries and samples.

* Updated docs and code.

* Added Switch Joycon sample.

Co-authored-by: mikee47 <[email protected]>
  • Loading branch information
slaff and mikee47 authored Jun 28, 2022
1 parent 694ed96 commit 2758617
Show file tree
Hide file tree
Showing 37 changed files with 1,255 additions and 8 deletions.
14 changes: 12 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,18 @@
#
# Esp32 libraries
#

### NONE ###
[submodule "Libraries.ESP32-BLE-Gamepad"]
path = Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad
url = https://github.com/lemmingDev/ESP32-BLE-Gamepad.git
ignore = dirty
[submodule "Libraries.ESP32-BLE-Keyboard"]
path = Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard
url = https://github.com/T-vK/ESP32-BLE-Keyboard.git
ignore = dirty
[submodule "Libraries.esp-nimble-cpp"]
path = Sming/Libraries/NimBLE/esp-nimble-cpp
url = https://github.com/h2zero/esp-nimble-cpp.git
ignore = dirty


#
Expand Down
54 changes: 52 additions & 2 deletions Sming/Arch/Esp32/Components/esp32/component.mk
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,22 @@ SDKCONFIG_H := $(SDK_BUILD_BASE)/config/sdkconfig.h

SDK_LIBDIRS := \
esp_wifi/lib/$(ESP_VARIANT) \
xtensa/$(ESP_VARIANT)/ \
hal/$(ESP_VARIANT)/ \
xtensa/$(ESP_VARIANT) \
hal/$(ESP_VARIANT) \
$(ESP_VARIANT)/ld \
esp_rom/$(ESP_VARIANT)/ld

# BLUETOOTH
ifeq ($(ESP_VARIANT),esp32)
SDK_LIBDIRS += bt/controller/lib_esp32/$(ESP_VARIANT)
ENABLE_BLUETOOTH := 1
else ifneq (,$(findstring $(ESP_VARIANT),esp32c3 esp32s3))
SDK_LIBDIRS += bt/controller/lib_esp32c3_family/$(ESP_VARIANT)
ENABLE_BLUETOOTH := 1
else
ENABLE_BLUETOOTH := 0
endif

ESP32_COMPONENT_PATH := $(COMPONENT_PATH)
SDK_DEFAULT_PATH := $(ESP32_COMPONENT_PATH)/sdk

Expand Down Expand Up @@ -71,6 +82,33 @@ SDK_INCDIRS := \
lwip/include/apps/sntp \
wpa_supplicant/include/esp_supplicant

ifeq ($(ENABLE_BLUETOOTH),1)
SDK_INCDIRS += \
bt/include/$(ESP_VARIANT)/include \
bt/common/api/include/api \
bt/common/btc/profile/esp/blufi/include \
bt/common/btc/profile/esp/include \
bt/common/osi/include \
bt/host/nimble/nimble/nimble/include \
bt/host/nimble/nimble/nimble/host/include \
bt/host/nimble/nimble/porting/nimble/include \
bt/host/nimble/nimble/porting/npl/freertos/include \
bt/host/nimble/nimble/nimble/host/services/ans/include \
bt/host/nimble/nimble/nimble/host/services/bas/include \
bt/host/nimble/nimble/nimble/host/services/dis/include \
bt/host/nimble/nimble/nimble/host/services/gap/include \
bt/host/nimble/nimble/nimble/host/services/gatt/include \
bt/host/nimble/nimble/nimble/host/services/ias/include \
bt/host/nimble/nimble/nimble/host/services/ipss/include \
bt/host/nimble/nimble/nimble/host/services/lls/include \
bt/host/nimble/nimble/nimble/host/services/tps/include \
bt/host/nimble/nimble/nimble/host/util/include \
bt/host/nimble/nimble/nimble/host/store/ram/include \
bt/host/nimble/nimble/nimble/host/store/config/include \
bt/host/nimble/esp-hci/include \
bt/host/nimble/port/include
endif

ifdef IDF_TARGET_ARCH_RISCV
SDK_INCDIRS += \
freertos/port/riscv/include \
Expand Down Expand Up @@ -151,6 +189,13 @@ SDK_ESP_WIFI_LIBS := \
pp \
smartconfig

ifeq ($(ENABLE_BLUETOOTH),1)
SDK_ESP_BLUETOOTH_LIBS := bt btdm_app
ifneq (,$(filter $(ESP_VARIANT),esp32c3 esp32s3))
SDK_ESP_BLUETOOTH_LIBS += btbb
endif
endif

ifeq ($(ESP_VARIANT),esp32)
SDK_ESP_WIFI_LIBS += rtc
endif
Expand All @@ -167,6 +212,11 @@ EXTRA_LIBS := \

ifneq ($(DISABLE_WIFI),1)
EXTRA_LIBS += $(SDK_ESP_WIFI_LIBS)

ifeq ($(ENABLE_BLUETOOTH),1)
EXTRA_LIBS += $(SDK_ESP_BLUETOOTH_LIBS)
endif

endif

LinkerScript = -T $(ESP_VARIANT).$1.ld
Expand Down
10 changes: 10 additions & 0 deletions Sming/Arch/Esp32/Components/esp32/sdk/config/common
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ CONFIG_ETH_USE_SPI_ETHERNET=y
CONFIG_ETH_SPI_ETHERNET_W5500=y
CONFIG_ETH_SPI_ETHERNET_DM9051=y

# Bluetooth
CONFIG_BT_ENABLED=y
CONFIG_BT_BLUEDROID_ENABLED=n
CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=n
CONFIG_BLE_MESH=n
CONFIG_BT_NIMBLE_MESH=n

CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=n

# Mandatory Sming framework changes
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=16384
CONFIG_ESP_TASK_WDT_TIMEOUT_S=8
Expand Down
7 changes: 3 additions & 4 deletions Sming/Arch/Esp32/Components/esp_wifi/README.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Esp8266 WiFi
============
Esp32 WiFi
==========

All related libraries for WiFi support. Definitions are provided in the
Espressif Non-OS SDK.
All related libraries for WiFi support.
1 change: 1 addition & 0 deletions Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad
Submodule ESP32-BLE-Gamepad added at 544dc6
65 changes: 65 additions & 0 deletions Sming/Libraries/BLEGamepad/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
ESP32 BLE Gamepad
=================

.. highlight:: c++

Introduction
------------
This library allows you to make the ESP32 act as a Bluetooth gamepad and control what it does.
The library uses :library:`NimBLE` for faster and lighter communication.

Features
--------

Using this library you can do the following:

- Button press (128 buttons)
- Button release (128 buttons)
- Axes movement (6 axes (16 bit) (x, y, z, rZ, rX, rY) --> (Left Thumb X, Left Thumb Y, Right Thumb X, Right Thumb Y, Left Trigger, Right Trigger))
- 2 Sliders (16 bit) (Slider 1 and Slider 2)
- 4 point of view hats (ie. d-pad plus 3 other hat switches)
- Simulation controls (rudder, throttle, accelerator, brake, steering)
- Configurable HID descriptor
- Report optional battery level to host (basically works, but it doesn't show up in Android's status bar)
- Customize Bluetooth device name/manufacturer
- Uses efficient NimBLE bluetooth library
- Compatible with Windows
- Compatible with Android (Android OS maps default buttons / axes / hats slightly differently than Windows)
- Compatible with Linux (limited testing)
- Compatible with MacOS X (limited testing)

Using
-----

1. Add ``COMPONENT_DEPENDS += BLEGamepad`` to your application componenent.mk file.
2. Add these lines to your application::

#include <BleGamepad.h>
namespace
{
BleGamepad bleGamepad;
// ...
} // namespace
void init()
{
// ...
bleGamepad.begin();
}


Notes
-----
By default, reports are sent on every button press/release or axis/slider/hat/simulation movement, however this can be disabled,
and then you manually call sendReport on the gamepad instance as shown in the IndividualAxes.ino example.

There is also Bluetooth specific information that you can use (optional):

Instead of ``BleGamepad bleGamepad;`` you can do ``BleGamepad bleGamepad("Bluetooth Device Name", "Bluetooth Device Manufacturer", 100);``.
The third parameter is the initial battery level of your device.
Adjusting the battery level later on doesn't work.
By default the battery level will be set to 100%, the device name will be `ESP32 BLE Gamepad` and the manufacturer will be `Espressif`.
8 changes: 8 additions & 0 deletions Sming/Libraries/BLEGamepad/component.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
COMPONENT_SUBMODULES := ESP32-BLE-Gamepad
COMPONENT_DEPENDS := NimBLE

COMPONENT_SRCDIRS := ESP32-BLE-Gamepad
COMPONENT_INCDIRS := $(COMPONENT_SRCDIRS)

COMPONENT_CPPFLAGS:= -DUSE_NIMBLE=1
APP_CFLAGS += -DUSE_NIMBLE=1
Empty file.
9 changes: 9 additions & 0 deletions Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#####################################################################
#### Please don't change this file. Use component.mk instead ####
#####################################################################

ifndef SMING_HOME
$(error SMING_HOME is not set: please configure it as an environment variable)
endif

include $(SMING_HOME)/project.mk
32 changes: 32 additions & 0 deletions Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Bluetooth Gamepad
=================

Introduction
------------
This sample turns the ESP32 into a Bluetooth LE gamepad that presses buttons and moves axis

Possible buttons are: BUTTON_1 through to BUTTON_16
(16 buttons supported by default. Library can be configured to support up to 128)

Possible DPAD/HAT switch position values are:
DPAD_CENTERED, DPAD_UP, DPAD_UP_RIGHT, DPAD_RIGHT, DPAD_DOWN_RIGHT, DPAD_DOWN, DPAD_DOWN_LEFT, DPAD_LEFT, DPAD_UP_LEFT
(or HAT_CENTERED, HAT_UP etc)

bleGamepad.setAxes takes the following int16_t parameters for the Left/Right Thumb X/Y, Left/Right Triggers plus slider1 and slider2, and hat switch position as above:
(Left Thumb X, Left Thumb Y, Right Thumb X, Right Thumb Y, Left Trigger, Right Trigger, Hat switch position ^ (1 hat switch (dpad) supported by default. Library can be configured to support up to 4)

Library can also be configured to support up to 5 simulation controls (can be set with setSimulationControls)
(rudder, throttle, accelerator, brake, steering), but they are not enabled by default.


Testing
-------

You can use one of the following applications on your PC to test and see all buttons that were clicked.

On Linux install ``jstest-gtk`` to test the ESP32 gamepad. Under Ubuntu this can be done by typing the following command::

sudo apt install jstest-gtk
On Windows use this `Windows test application <http://www.planetpointy.co.uk/joystick-test-application/>`__.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include <SmingCore.h>
#include <BleGamepad.h>

namespace
{
BleGamepad bleGamepad;

Timer procTimer;

void loop()
{
if(!bleGamepad.isConnected()) {
return;
}

Serial.println("Press buttons 5 and 16. Move all enabled axes to max. Set DPAD (hat 1) to down right.");
bleGamepad.press(BUTTON_5);
bleGamepad.press(BUTTON_16);
bleGamepad.setAxes(32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, DPAD_DOWN_RIGHT);
// All axes, sliders, hats etc can also be set independently. See the IndividualAxes.ino example
delay(500);

Serial.println("Release button 5. Move all axes to min. Set DPAD (hat 1) to centred.");
bleGamepad.release(BUTTON_5);
bleGamepad.setAxes(-32767, -32767, -32767, -32767, -32767, -32767, -32767, -32767, DPAD_CENTERED);
delay(500);
}

} // namespace

void init()
{
Serial.begin(COM_SPEED_SERIAL);
Serial.println("Starting BLE Gamepad sample!");
bleGamepad.begin();
// The default bleGamepad.begin() above is the same as bleGamepad.begin(16, 1, true, true, true, true, true, true, true, true, false, false, false, false, false);
// which enables a gamepad with 16 buttons, 1 hat switch, enabled x, y, z, rZ, rX, rY, slider 1, slider 2 and disabled rudder, throttle, accelerator, brake, steering
// Auto reporting is enabled by default.
// Use bleGamepad.setAutoReport(false); to disable auto reporting, and then use bleGamepad.sendReport(); as needed

procTimer.initializeMs(500, loop).start();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
COMPONENT_DEPENDS := BLEGamepad
1 change: 1 addition & 0 deletions Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard
Submodule ESP32-BLE-Keyboard added at f8dd48
16 changes: 16 additions & 0 deletions Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
diff --git a/BleKeyboard.cpp b/BleKeyboard.cpp
index 0d043f4..3c2677c 100644
--- a/BleKeyboard.cpp
+++ b/BleKeyboard.cpp
@@ -539,8 +539,8 @@ void BleKeyboard::delay_ms(uint64_t ms) {
if(ms){
uint64_t e = (m + (ms * 1000));
if(m > e){ //overflow
- while(esp_timer_get_time() > e) { }
+ while(uint64_t(esp_timer_get_time()) > e) { }
}
- while(esp_timer_get_time() < e) {}
+ while(uint64_t(esp_timer_get_time()) < e) {}
}
}
\ No newline at end of file
81 changes: 81 additions & 0 deletions Sming/Libraries/BLEKeyboard/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
ESP32 BLE Keyboard
==================

.. highlight:: c++

Introduction
------------
This library allows you to make the ESP32 act as a Bluetooth keyboard and control what it does.
The library uses :library:`NimBLE` for faster and lighter communication.

Features
--------

Using this library you can do the following:

- Send key strokes
- Send text
- Press/release individual keys
- Media keys are supported
- Set battery level (basically works, but doesn't show up in Android's status bar)
- Compatible with Android
- Compatible with Windows
- Compatible with Linux
- Compatible with MacOS X (not stable, some people have issues, doesn't work with old devices)
- Compatible with iOS (not stable, some people have issues, doesn't work with old devices)

Using
-----

1. Add ``COMPONENT_DEPENDS += BLEKeyboard`` to your application componenent.mk file.
2. Add these lines to your application::

#include <BleKeyboard.h>

namespace
{
BleKeyboard bleKeyboard;
// ...
} // namespace
void init()
{
// ...
bleKeyboard.begin();
}


API documentation
-----------------
The BleKeyboard interface is almost identical to the Keyboard Interface, so you can use documentation right here:
https://www.arduino.cc/reference/en/language/functions/usb/keyboard/

In addition to that you can send media keys (which is not possible with the USB keyboard library). Supported are the following:

- KEY_MEDIA_NEXT_TRACK
- KEY_MEDIA_PREVIOUS_TRACK
- KEY_MEDIA_STOP
- KEY_MEDIA_PLAY_PAUSE
- KEY_MEDIA_MUTE
- KEY_MEDIA_VOLUME_UP
- KEY_MEDIA_VOLUME_DOWN
- KEY_MEDIA_WWW_HOME
- KEY_MEDIA_LOCAL_MACHINE_BROWSER // Opens "My Computer" on Windows
- KEY_MEDIA_CALCULATOR
- KEY_MEDIA_WWW_BOOKMARKS
- KEY_MEDIA_WWW_SEARCH
- KEY_MEDIA_WWW_STOP
- KEY_MEDIA_WWW_BACK
- KEY_MEDIA_CONSUMER_CONTROL_CONFIGURATION // Media Selection
- KEY_MEDIA_EMAIL_READER

There is also Bluetooth specific information that you can set (optional):
Instead of ``BleKeyboard bleKeyboard;`` you can do ``BleKeyboard bleKeyboard("Bluetooth Device Name", "Bluetooth Device Manufacturer", 100);``. (Max length is 15 characters, anything beyond that will be truncated.)
The third parameter is the initial battery level of your device. To adjust the battery level later on you can simply call e.g. ``bleKeyboard.setBatteryLevel(50)`` (set battery level to 50%).
By default the battery level will be set to 100%, the device name will be `ESP32 Bluetooth Keyboard` and the manufacturer will be `Espressif`.
There is also a ``setDelay`` method to set a delay between each key event. E.g. ``bleKeyboard.setDelay(10)`` (10 milliseconds). The default is `8`.
This feature is meant to compensate for some applications and devices that can't handle fast input and will skip letters if too many keys are sent in a small time frame.
Loading

0 comments on commit 2758617

Please sign in to comment.