This project's canonical repositories is hosted on Gothel Software.
Goals
This project aims to create a clean, modern and easy to use API for
Bluetooth
LE and BREDR, fully accessible through C++, Java and other
languages.
Overview
Direct-BT provides direct Bluetooth
LE and BREDR programming, offering robust high-performance support
for embedded & desktop with zero overhead via C++ and Java.
Direct-BT supports a fully event driven workflow from
adapter management via device discovery to GATT programming. using its
platform agnostic HCI, L2CAP, SMP and GATT client-side protocol
implementation.
Direct-BT may be utilized via its C++
API or via its Java
API.
Direct-BT is exposed via the following native libraries
libdirect_bt.so for the core C++ implementation.
libjavadirect_bt.so for the Java binding.
Direct-BT is C++17 conform and shall upgrade towards C++20
when widely available on all target platforms.
Some elaboration on the implementation details
The host-side of HCI, L2CAP etc is usually implemented within the OS,
e.g. Linux/BlueZ Kernel. These layers communicate with the
actual BT controller and the user application, acting as the
middleman.
Direct-BT offers packet types and handler facilities for
HCI, L2CAP, SMP, ATT-PDU and GATT (as well to Linux/BlueZ-Mngr)
to communicate with these universal host-side Bluetooth layers and hence
to reach-out to devices.
Implementation Status
LE master/client mode is fully supported to work with LE BT
devices.
LE slave/server mode (peripheral) is fully supported with LE
BT devices:
BTRole separation (master/slave)
Advertising
GATT Server with user code interaction via listener
Slave / Server SMP Security, reusing persisting SMPKeyBin
files.
SMP LE Secure Connections and LE legacy pairing is
fully supported, exposing BTSecurityLevel and SMPIOCapability setup per
connection and providing automatic security mode
negotiation.
Provoding dbt_repeater00, a BT repeater forwading
between GATT-Server and -Client, allowing protocol
analysis between an external client and server.
Online unit testing with two BT adapter is provided.
BREDR support is planned and prepared for.
To support other platforms than Linux/BlueZ, we will have to
move specified HCI host features used in DBTManager to HCIHandler,
SMPHandler,.. - and -
add specialization for each new platform using their
non-platform-agnostic features.
Since Direct-BT is not using a 3rd party Bluetooth client
library or daemon/service, they should be disabled to allow operation
without any interference. To disable the BlueZ D-Bus userspace
daemon bluetoothd via systemd, you may use the following
commands.
systemctl stop bluetooth
systemctl disable bluetooth
systemctl mask bluetooth
Required
Permissions for Direct-BT Applications
Since Direct-BT requires root permissions to certain
Bluetooth network device facilities, non-root user require to be granted
such permissions.
For GNU/Linux, there permissions are called capabilities. The
following capabilites are required
CAP_NET_RAW (Raw HCI access)
CAP_NET_ADMIN (Additional raw HCI access plus (re-)setting
the adapter etc)
On Debian >= 11 and Ubuntu >= 20.04 we can use package
libcap2-bin, version 1:2.44-1, which provides
the binaries /sbin/setcap and /sbin/getcap. It
depends on package libcap2, version
>= 1:2.33. If using earlier setcap
binaries, your mileage may vary (YMMV).
Launch as root
In case your platform lacks support for mentioned
setcap, you may need to execute your application as root
using sudo, e.g.:
Notable here is that capsh needs to be invoked by root to
hand over the capabilities and to pass over the
cap_net_raw,cap_net_admin+eip via --addamb=... it also
needs cap_setpcap,cap_setuid,cap_setgid+ep beforehand.
Launch Examples
The capsh method (default), setcap and
root method is being utilized in
This project also uses the Jau Library as a
git submodule, which has been extracted earlier from this project to
better encapsulation and allow general use.
Direct-BT does not require GLib/GIO nor shall the
BlueZ userspace service bluetoothd be active for best
experience.
To disable the bluetoothd service using systemd:
systemctl stop bluetooth
systemctl disable bluetooth
systemctl mask bluetooth
Build Dependencies
CMake 3.13+ but >= 3.18 is recommended
GCC >= 8.3.0 (g++)
or clang >= 10.0
libunwind8 >= 1.2.1
For Java support
OpenJDK >= 11.
junit4 >= 4.12
Installing build dependencies for Debian >= 10 and Ubuntu >=
18.04:
CPU_COUNT=`getconf _NPROCESSORS_ONLN`
git clone --recurse-submodules git://jausoft.com/srv/scm/direct_bt.git
cd direct_bt
mkdir build
cd build
cmake -DBUILDJAVA=ON -DBUILDEXAMPLES=ON -DBUILD_TESTING=ON ..
make -j $CPU_COUNT install test doc
The install target of the last command will create the include/ and
lib/ directories with a copy of the headers and library objects
respectively in your build location. Note that doing an out-of-source
build may cause issues when rebuilding later on.
Our cmake configure has a number of options, cmake-gui or
ccmake can show you all the options. The interesting ones are
detailed below:
Changing install path from /usr/local to /usr
-DCMAKE_INSTALL_PREFIX=/usr
Building debug build:
-DDEBUG=ON
Building with enabled testing, i.e. offline testing without
any potential interaction as user:
-DBUILD_TESTING=ON
Building with enabled trial and testing , i.e. live
testing with 2 Bluetooth adapter and potential sudo interaction:
-DBUILD_TRIAL=ON
Disable stripping native lib even in non debug build:
-DUSE_STRIP=OFF
Disable using libunwind (default: enabled for all but
arm32, armhf)
Building with enabled testing, i.e. offline testing without
any potential interaction as user is provided via the cmake
build argument -DBUILD_TESTING=ON, see above.
Building with enabled trial and testing , i.e. live
testing with 2 Bluetooth adapter is provided via the cmake
build argument -DBUILD_TRIAL=ON, see above.
The trial tests utilize one or more actual Bluetooth
adapter, hence using the capsh launch for the required
permissions as described above. Therefor, sudo will be called
and a user interaction to enter the sudo password may
occur.
The trial tests cover Direct-BT's Bluetooth
functionality, having its master/client and slave/server
peripheral facilities communicating via actual adapter, supporting
regression testing of the API, its implementation and adapter.
The trial tests take around 110 seconds, since
TestDBClientServer1* performs the test twelve fold
altogether:
Two fold between installed adapter in both directions
Three fold w/o encryption, in legacy mode (SC 0) and secure
connections (SC 1)
Two fold each test
without encryption just twice
with encryption
with ENC_ONLY encryption and initial key pairing
with ENC_ONLY encryption and reusing pre-paired
keys
All tests pass reproducible using two well working adapter, e.g.
Raspi 3b+ (BT4) and CSR (BT4).
1/7 legacy security (SC 0) tests using at least one not well working
BT5 adapter may timeout waiting for key completion. The following issues
are known and are under investigation:
BlueZ is not sending us all new key information under
legacy security (SC 0) using at least one BT5 adapter
This is mitigated by BTAdapter's smp_watchdog,
leading to a retrial visible as SMP Timeout
If the solution is not there, please search for an existing issue in
our Bugzilla
DB, please contact us for a new
bugzilla account via email to Sven Gothel [email protected].
Contributing to Direct-BT
You shall agree to Developer Certificate of Origin and Sign-off your
code, using a real name and e-mail address.
Please check the Contribution document
for more details.
Historical Notes
Direct-BT Origins
Direct-BT development started around April 2020, initially
as an alternative TinyB Java-API implementation.
The work was motivated due to strict performance, discovery- and
connection timing requirements, as well as being able to handle multiple
devices concurrently using a real-time event driven low-overhead
architecture.
Zafena's POC-Workstation
was originally implemented using TinyB and hence the D-Bus
layer to the BlueZ client library.
Real time knowledge when devices are discovered and connected were
not available and cloaked by the caching mechanism. Advertising
package details were not exposed.
Connections attempts often took up to 10 seconds to be completed.
Detailed information from the Bluetooth layer were inaccessible
including detailed error states.
Fine grained control about discovery and connection parameter were
not exposed by the D-Bus API and hence TinyB.
In January 2020 we tried to remedy certain aspects to meet our goals,
but concluded to require direct Bluetooth control via the
BlueZ/Linux kernel implementation.
Direct-BT was born.
We then implemented data types for
HCI Packets to handle HCI communication with the
adapter
Mgmt Packets to support BlueZ/Linux
communication
ATT PDU Messages to handle GATT communication with the
remote device
SMP Packets to implement Secure Connections (SC)
and Legacy pairing.
Last but not least we added
Bluetooth version 5 support
GATT-Server support to enable implementing
peripheral devices, as well as to allow self-testing of
Direct-BT.
Today, Direct-BT's C++ and Java API match 1:1 and shall not
contain legacy API artifacts.
TinyB Removal since version
2.3
Heading towards feature completion for Direct-BT, we
completely removed the previously refactored TinyB.
Detailing full Bluetooth support in Direct-BT
including the addition of GATT-Server support rendered TinyB an
obstacle for the public API.
However, TinyB inspired us and was a great reference
implementation while developing and testing Direct-BT.
We like to thank the authors of TinyB for their great work
helping others and us moving forward. Thank you!
TinyB
TinyB was developed by the Intel Corporation and
its main authors were
Add BTObject::checkValid() implementation overriding jau:JavaUplink,
to actually validate whether instance is still valid.
2.5.0
Added DiscoveryPolicy, allowing fine tuned discovery
keep-alive policy and covering HCI host OS's implied discovery turn-off
when connected (BlueZ/Linux). API change of
BTAdapter::startDiscovery(..) and
AdapterStatusListener::discoveringChanged(..)
BTDevice::connectGATT(): Discover GATT services and parse
GenericAccess ASAP before
AdapterStatusListener::deviceReady()
SMPKeyBin::createAndWrite(..): Drop 'overwrite' argument as we shall
set
overwrite = PairingMode::PRE_PAIRED != device.getPairingMode()
Fix PRE_PAIRED mode for !SC (legacy): Master needs to
upload init LTK 1st, then responder LTK (regression)
Robustness: Reader-Callback Shutdown after 8s and use SC atomic for
state
BTAdapter::startDiscovery(..): Add 'bool filter_dup=true' as last
parameter
Unlock mutex before notify_all to avoid pessimistic
re-block of notified wait() thread
2.4.0
Completed Java support for LE slave/server (peripheral)
mode incl GATT-Server.
Added Link-Key support in our SMP processing and SMPKeyBin,
supporting non-legacy SC.
Aligned BTGatt* findGatt*() methods across
Java/C++
Moved EUI48, EUI48Sub (C++/Java) and
uuid_t, Octets (C++) to jaulib
for general use.
Added BTRole and GATTRole for full master/client and slave/server
support.
Added BTAdapter advertising support
Only use and program selected BTAdapter via BTAdapter::initialize()
(required now)
Supports using multiple applications, each using one adapter,
or
One application using multiple adapter for different tasks and
BTRole
2.3.0
Removal of TinyB
2.2.14
Bluetooth 5.0 Support
Using HCI extended scanning and connecting if supported (old API may
not work on new adapter)
Parsing and translating extended and enhanced event types, etc
TODO: User selection of LE_2M and
L2_CODED, ... ???
2.2.13
Revised API: BTGattChar::addCharListener(..) in C++ and Java for a
more intuitive use.
Fix EUI48Sub::scanEUI48Sub(..): Fail on missing expected colon, i.e.
after each two digits
Fix JNIAdapterStatusListener::deviceConnected(..): NewObject(..,
deviceClazzCtor, ..) used wrong argument order
2.2.11
Fix EUI48 unit test and refine on application permissions for
launching applications
Make BTDeviceRegistry and
BTSecurityRegistry universal
Move BTDeviceRegistry and
BTSecurityRegistry to direct_bt library (from
examples)
EUI48Sub: Complement with hash_code(),
clear(), indexOf(), contains(),
...
SMPKeyBin: Tighten constraints, readAndApply(..) must
validate minSecLevel.
BTAdapter::mgmtEvDeviceFoundHCI(..): Clarify code path,
covering name change via AD EIR.
Passthrough all paramter BTAdapter::startDiscovery(..)
-> HCIHandler::le_set_scan_param(..): Add
le_scan_active and filter_policy. Active
scanning is used to gather device name in discovery mode (AD EIR).
Add -dbt_debug argument for AD EIR
direct_bt.debug.hci.scan_ad_eir and parse EIR GAPFlags
Fix BTGattHandler: Gather all Descriptors from all Characteristics
(only queried 1st Char.)
SMPKeyBin's base filename compatibility with FAT32 Long Filename
(LFN)
2.2.5
Complete SMPKeyBin user API: Convenient static 'one shot' entries +
support no-encryption case
Fix leaked AdapterStatusListener
Fixed HCIHandler and l2cap related issues
Unified free function to_string(..) and member toString()
Tested key regeneration use-case: Pairing failure (bad key), key
removal and auto security negotiation.
Adding SMPKeyBin file removal support.
Tested negative passkey/boolean input, requested via auto security
negotiation.
Using negative passkey response via
setPairingPasskey(passkey = 0) for performance.
2.2.4
Providing full featured SMPKeyBin for LTK, CSRK and
secure connection param setup persistence and upload.
Added Auto Security mode, negotiating the security setup with any
device.
Bugfixes in HCIHandler and ACL/SMP packet processing.
Enhanced robusteness of underlying C++ API and implementation.
2.2.00
Kicked off junit testing for Java implementation
Adding direct_bt-fat.jar (fat jar) bootstrapping its
contained native libraries using merged-in jaulib.
Java API renaming, incl package: org.tinyb to
org.direct_bt.
Completing SMP/Security implementation (WIP)
Replaced std::vector and jau::cow_vector with jau::darray and
jau::cow_darray
2.1.33
Added AdapterStatusListener callback methods devicePairingState(..)
and deviceReady(..), supporting security/pairing.
Added support for LE Secure Connections and LE legacy
pairing utilizing SMP and BlueZ/Kernel features.
Exposing BTSecurityLevel and SMPIOCapability for connection oriented
security setup on BlueZ/Kernel, see DBTDevice and BluetoothDevice.
Covering SMP over L2CAP messaging via SMPPDUMsg types and retrieval
via HCI/ACL/L2CAP on BlueZ/Kernel
2.1.30
Use read lock-free jau::cow_vector for all callback-lists, avoiding
locks in callback iteration
Passed GCC all warnings, compile clean
Passed GCC sanitizer runtime checks
Using extracted Jau C++ Support Library, enhanced
encapsulation
Passed valgrind's memcheck, helgrind and drd validating no memory
leak nor data race or deadlock using dbt_scanner10
Added native de-mangled backtrace support using libunwind
and and abi::__cxa_demangle
Reaching robust implementation state of Direct-BT,
including recovery from L2CAP transmission breakdown on Raspberry
Pi.
Resolved race conditions on rapid device discovery and connect,
using one thread per device.
API documentation with examples
Tested on GNU/Linux x86_64, arm32 and arm64 with native and Java
examples.
Tested on Bluetooth Adapter: Intel, CSR and Raspberry Pi
Almost removed non-standard Linux/BlueZ-Mngr kernel
dependency using the universal HCI protocol, remaining portion
configures the adapter.
2.0.0
Java D-Bus implementation details of package 'tinyb' moved to
tinyb.dbus.
The tinyb.jar jar file has been renamed to
tinyb2.jar, avoiding conflicts.
General interfaces matching the original implementation and
following BlueZ
API were created in package org.tinyb.
Class org.tinyb.BluetoothFactory provides a factory to
instantiate the initial root org.tinyb.BluetoothManager, either
using the original D-Bus implementation or an alternative
implementation.
C++ namespace and implementation kept unchanged.
0.5.0
Added notifications API
Capitalized RSSI and UUID properly in Java
Added JNI Helper classes for managing lifetime of JNIEnv and Global
Refences
0.4.0
Added asynchronous methods for discovering BluetoothObjects