Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
dbt_scanner00.cpp

This C++ direct_bt scanner example is a TinyB backward compatible and not fully event driven.It uses a more simple high-level approach via semantic GATT types (Service, Characteristic, ..) without bothering with fine implementation details of GATTHandler.

For a more technical and low-level approach see dbt_scanner01.cpp!

This example does not represent the recommended utilization of Direct-BT.

/*
* Author: Sven Gothel <sgothel@jausoft.com>
* Copyright (c) 2020 Gothel Software e.K.
* Copyright (c) 2020 ZAFENA AB
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <cinttypes>
extern "C" {
#include <unistd.h>
}
using namespace direct_bt;
using namespace jau;
/**
* This C++ direct_bt scanner example is a TinyB backward compatible and not fully event driven.
* It uses a more simple high-level approach via semantic GATT types (Service, Characteristic, ..)
* without bothering with fine implementation details of BTGattHandler.
* <p>
* For a more technical and low-level approach see dbt_scanner01.cpp!
* </p>
* <p>
* This example does not represent the recommended utilization of Direct-BT.
* </p>
*/
std::shared_ptr<BTDevice> deviceFound = nullptr;
std::mutex mtxDeviceFound;
std::condition_variable cvDeviceFound;
void adapterSettingsChanged(BTAdapter &a, const AdapterSetting oldmask, const AdapterSetting newmask,
const AdapterSetting changedmask, const uint64_t timestamp) override {
fprintf(stderr, "****** Native Adapter SETTINGS_CHANGED: %s -> %s, changed %s\n",
to_string(oldmask).c_str(),
to_string(newmask).c_str(),
to_string(changedmask).c_str());
fprintf(stderr, "Status BTAdapter:\n");
fprintf(stderr, "%s\n", a.toString().c_str());
(void)timestamp;
}
void discoveringChanged(BTAdapter &a, const ScanType currentMeta, const ScanType changedType, const bool changedEnabled, const bool keepAlive, const uint64_t timestamp) override {
fprintf(stderr, "****** DISCOVERING: meta %s, changed[%s, enabled %d, keepAlive %d]: %s\n",
to_string(currentMeta).c_str(), to_string(changedType).c_str(), changedEnabled, keepAlive, a.toString().c_str());
(void)timestamp;
}
bool deviceFound(std::shared_ptr<BTDevice> device, const uint64_t timestamp) override {
fprintf(stderr, "****** FOUND__: %s\n", device->toString(true).c_str());
fprintf(stderr, "Status Adapter:\n");
fprintf(stderr, "%s\n", device->getAdapter().toString().c_str());
{
std::unique_lock<std::mutex> lockRead(mtxDeviceFound); // RAII-style acquire and relinquish via destructor
::deviceFound = device;
cvDeviceFound.notify_all(); // notify waiting getter
return true;
}
(void)timestamp;
}
void deviceUpdated(std::shared_ptr<BTDevice> device, const EIRDataType updateMask, const uint64_t timestamp) override {
fprintf(stderr, "****** UPDATED: %s of %s\n", to_string(updateMask).c_str(), device->toString(true).c_str());
(void)timestamp;
}
void deviceConnected(std::shared_ptr<BTDevice> device, const uint16_t handle, const uint64_t timestamp) override {
fprintf(stderr, "****** CONNECTED: %s\n", device->toString(true).c_str());
(void)handle;
(void)timestamp;
}
void devicePairingState(std::shared_ptr<BTDevice> device, const SMPPairingState state, const PairingMode mode, const uint64_t timestamp) override {
fprintf(stderr, "****** PAIRING STATE: state %s, mode %s, %s\n",
to_string(state).c_str(), to_string(mode).c_str(), device->toString().c_str());
(void)timestamp;
}
void deviceReady(std::shared_ptr<BTDevice> device, const uint64_t timestamp) override {
fprintf(stderr, "****** READY: %s\n", device->toString().c_str());
(void)timestamp;
}
void deviceDisconnected(std::shared_ptr<BTDevice> device, const HCIStatusCode reason, const uint16_t handle, const uint64_t timestamp) override {
fprintf(stderr, "****** DISCONNECTED: Reason 0x%X (%s), old handle %s: %s\n",
static_cast<uint8_t>(reason), to_string(reason).c_str(),
to_hexstring(handle).c_str(), device->toString(true).c_str());
(void)handle;
(void)timestamp;
}
std::string toString() const override {
return "MyAdapterStatusListener[this "+to_hexstring(this)+"]";
}
};
public:
void notificationReceived(BTGattCharRef charDecl, const TROOctets& charValue, const uint64_t timestamp) override {
const std::shared_ptr<BTDevice> dev = charDecl->getDeviceChecked();
const uint64_t tR = getCurrentMilliseconds();
fprintf(stderr, "****** GATT Notify (td %" PRIu64 " ms, dev-discovered %" PRIu64 " ms): From %s\n",
(tR-timestamp), (tR-dev->ts_creation), dev->toString().c_str());
if( nullptr != charDecl ) {
fprintf(stderr, "****** decl %s\n", charDecl->toString().c_str());
}
fprintf(stderr, "****** rawv %s\n", charValue.toString().c_str());
}
void indicationReceived(BTGattCharRef charDecl,
const TROOctets& charValue, const uint64_t timestamp,
const bool confirmationSent) override
{
const std::shared_ptr<BTDevice> dev = charDecl->getDeviceChecked();
const uint64_t tR = getCurrentMilliseconds();
fprintf(stderr, "****** GATT Indication (confirmed %d, td(msg %" PRIu64 " ms, dev-discovered %" PRIu64 " ms): From %s\n",
confirmationSent, (tR-timestamp), (tR-dev->ts_creation), dev->toString().c_str());
if( nullptr != charDecl ) {
fprintf(stderr, "****** decl %s\n", charDecl->toString().c_str());
if( _TEMPERATURE_MEASUREMENT == *charDecl->value_type ) {
std::shared_ptr<GattTemperatureMeasurement> temp = GattTemperatureMeasurement::get(charValue);
if( nullptr != temp ) {
fprintf(stderr, "****** valu %s\n", temp->toString().c_str());
}
}
}
fprintf(stderr, "****** rawv %s\n", charValue.toString().c_str());
}
};
int main(int argc, char *argv[])
{
bool ok = true, foundDevice=false;
int dev_id = 0; // default
bool waitForEnter=false;
bool forever = false;
/**
* BT Core Spec v5.2: Vol 3, Part A L2CAP Spec: 7.9 PRIORITIZING DATA OVER HCI
*
* In order for guaranteed channels to meet their guarantees,
* L2CAP should prioritize traffic over the HCI transport in devices that support HCI.
* Packets for Guaranteed channels should receive higher priority than packets for Best Effort channels.
* ...
* I have noticed that w/o HCI le_connect, overall communication takes twice as long!!!
*/
bool doHCI_Connect = true;
for(int i=1; i<argc; i++) {
if( !strcmp("-wait", argv[i]) ) {
waitForEnter = true;
} else if( !strcmp("-forever", argv[i]) ) {
forever = true;
} else if( !strcmp("-dev_id", argv[i]) && argc > (i+1) ) {
dev_id = atoi(argv[++i]);
} else if( !strcmp("-skipConnect", argv[i]) ) {
doHCI_Connect = false;
} else if( !strcmp("-mac", argv[i]) && argc > (i+1) ) {
std::string macstr = std::string(argv[++i]);
}
}
fprintf(stderr, "dev_id %d\n", dev_id);
fprintf(stderr, "doHCI_Connect %d\n", doHCI_Connect);
fprintf(stderr, "waitForDevice: %s\n", waitForDevice.toString().c_str());
if( waitForEnter ) {
fprintf(stderr, "Press ENTER to continue\n");
getchar();
}
std::shared_ptr<BTAdapter> adapter = mngr.getAdapter(dev_id);
if( nullptr == adapter ) {
fprintf(stderr, "adapter dev_id %d not available.\n", dev_id);
exit(1);
}
if( !adapter->isValid() ) {
fprintf(stderr, "Adapter invalid: %s\n", adapter->toString().c_str());
exit(1);
}
if( !adapter->isPowered() ) {
fprintf(stderr, "Adapter not powered: %s\n", adapter->toString().c_str());
exit(1);
}
fprintf(stderr, "Using adapter: %s\n", adapter->toString().c_str());
adapter->addStatusListener(std::shared_ptr<AdapterStatusListener>(new MyAdapterStatusListener()));
const uint64_t t0 = getCurrentMilliseconds();
while( ok && ( forever || !foundDevice ) ) {
ok = HCIStatusCode::SUCCESS == adapter->startDiscovery(true /* keepAlive */);
if( !ok) {
perror("Adapter start discovery failed");
goto out;
}
std::shared_ptr<BTDevice> device = nullptr;
{
std::unique_lock<std::mutex> lockRead(mtxDeviceFound); // RAII-style acquire and relinquish via destructor
while( nullptr == device ) { // FIXME deadlock, waiting forever!
cvDeviceFound.wait(lockRead);
if( nullptr != deviceFound ) {
foundDevice = deviceFound->getAddressAndType().matches(waitForDevice); // match
if( foundDevice || ( BDAddressAndType::ANY_DEVICE == waitForDevice && deviceFound->getAddressAndType().isLEAddress() ) ) {
// match or any LE device
device.swap(deviceFound); // take over deviceFound
}
}
}
}
adapter->stopDiscovery();
if( ok && nullptr != device ) {
const uint64_t t1 = getCurrentMilliseconds();
//
// HCI LE-Connect
// (Without: Overall communication takes ~twice as long!!!)
//
if( doHCI_Connect ) {
if( ( res = device->connectDefault() ) != HCIStatusCode::SUCCESS ) {
fprintf(stderr, "Connect: Failed res %s, %s\n", to_string(res).c_str(), device->toString().c_str());
// we tolerate the failed immediate connect, as it might happen at a later time
} else {
fprintf(stderr, "Connect: Success\n");
}
} else {
fprintf(stderr, "Connect: Skipped %s\n", device->toString().c_str());
}
//
// GATT Service Processing
//
jau::darray<BTGattServiceRef> primServices = device->getGattServices(); // implicit GATT connect...
if( primServices.size() > 0 ) {
const uint64_t t5 = getCurrentMilliseconds();
{
const uint64_t td15 = t5 - t1; // discovered -> connect -> gatt complete
const uint64_t td05 = t5 - t0; // total
fprintf(stderr, "\n\n\n");
fprintf(stderr, "GATT primary-services completed\n");
fprintf(stderr, " discovery-done to gatt complete %" PRIu64 " ms,\n"
" discovered to gatt complete %" PRIu64 " ms,\n"
" total %" PRIu64 " ms\n\n",
td15, (t5 - device->getCreationTimestamp()), td05);
}
std::shared_ptr<GattGenericAccessSvc> ga = device->getGattGenericAccess();
if( nullptr != ga ) {
fprintf(stderr, " GenericAccess: %s\n\n", ga->toString().c_str());
}
{
std::shared_ptr<BTGattHandler> gatt = device->getGattHandler();
if( nullptr != gatt && gatt->isConnected() ) {
std::shared_ptr<GattDeviceInformationSvc> di = gatt->getDeviceInformation(primServices);
if( nullptr != di ) {
fprintf(stderr, " DeviceInformation: %s\n\n", di->toString().c_str());
}
}
}
for(size_t i=0; i<primServices.size(); i++) {
BTGattService & primService = *primServices.at(i);
fprintf(stderr, " [%2.2d] Service %s\n", (int)i, primService.toString().c_str());
fprintf(stderr, " [%2.2d] Service Characteristics\n", (int)i);
jau::darray<BTGattCharRef> & serviceCharacteristics = primService.characteristicList;
for(size_t j=0; j<serviceCharacteristics.size(); j++) {
BTGattChar & serviceChar = *serviceCharacteristics.at(j);
fprintf(stderr, " [%2.2d.%2.2d] Decla: %s\n", (int)i, (int)j, serviceChar.toString().c_str());
if( serviceChar.readValue(value) ) {
std::string sval = dfa_utf8_decode(value.get_ptr(), value.getSize());
fprintf(stderr, " [%2.2d.%2.2d] Value: %s ('%s')\n", (int)i, (int)j, value.toString().c_str(), sval.c_str());
}
}
bool cccdEnableResult[2];
bool cccdRet = serviceChar.configNotificationIndication(true /* enableNotification */, true /* enableIndication */, cccdEnableResult);
fprintf(stderr, " [%2.2d.%2.2d] Config Notification(%d), Indication(%d): Result %d\n",
(int)i, (int)j, cccdEnableResult[0], cccdEnableResult[1], cccdRet);
if( cccdRet ) {
serviceChar.addCharListener( std::shared_ptr<BTGattChar::Listener>( new MyGATTEventListener() ) );
}
}
}
// FIXME sleep 1s for potential callbacks ..
sleep(1);
}
device->disconnect(); // OK if not connected, also issues device->disconnectGATT() -> gatt->disconnect()
} // if( ok && nullptr != device )
}
out:
return 0;
}
direct_bt::BTGattService::characteristicList
jau::darray< BTGattCharRef > characteristicList
List of Characteristic Declarations as shared reference.
Definition: BTGattService.hpp:97
direct_bt::BTAdapter::stopDiscovery
HCIStatusCode stopDiscovery() noexcept
Closes the discovery session.
Definition: BTAdapter.cpp:756
direct_bt::BTDevice::connectDefault
HCIStatusCode connectDefault() noexcept
Establish a default HCI connection to this device, using certain default parameter.
Definition: BTDevice.cpp:532
jau::darray::at
const_reference at(size_type i) const
Like std::vector::at(size_type), immutable reference.
Definition: darray.hpp:719
direct_bt::AdapterSetting
AdapterSetting
Adapter Setting Bits.
Definition: BTTypes1.hpp:136
DirectBT.hpp
direct_bt::BTGattHandler::getDeviceInformation
std::shared_ptr< GattDeviceInformationSvc > getDeviceInformation(jau::darray< BTGattServiceRef > &primServices)
Definition: BTGattHandler.cpp:1096
direct_bt::BTGattChar::hasProperties
bool hasProperties(const PropertyBitVal v) const noexcept
Definition: BTGattChar.hpp:216
direct_bt::GattGenericAccessSvc::toString
std::string toString() const noexcept
Definition: GATTNumbers.cpp:382
direct_bt::GattTemperatureMeasurement::get
static std::shared_ptr< GattTemperatureMeasurement > get(const TROOctets &source) noexcept
Definition: GATTNumbers.cpp:414
direct_bt::BDAddressAndType::ANY_DEVICE
static const BDAddressAndType ANY_DEVICE
Using EUI48::ANY_DEVICE and BDAddressType::BDADDR_UNDEFINED to match any device.
Definition: BTAddress.hpp:426
direct_bt::EIRDataType
EIRDataType
Bit mask of 'Extended Inquiry Response' (EIR) data fields, indicating a set of related data.
Definition: BTTypes0.hpp:752
direct_bt::BTGattChar::readValue
bool readValue(POctets &res, int expectedLength=-1)
BT Core Spec v5.2: Vol 3, Part G GATT: 4.8.1 Read Characteristic Value.
Definition: BTGattChar.cpp:304
dfa_utf8_decode.hpp
direct_bt
Definition: ATTPDUTypes.hpp:171
_TEMPERATURE_MEASUREMENT
static const uuid16_t _TEMPERATURE_MEASUREMENT(GattCharacteristicType::TEMPERATURE_MEASUREMENT)
direct_bt::BTGattChar
Definition: BTGattChar.hpp:75
direct_bt::AdapterStatusListener
BTAdapter status listener for BTDevice discovery events: Added, updated and removed; as well as for c...
Definition: BTAdapter.hpp:67
direct_bt::uuid16_t
Definition: UUID.hpp:98
direct_bt::BDAddressAndType::toString
std::string toString() const noexcept
Definition: BTTypes0.cpp:333
jau
Definition: basic_algos.hpp:34
direct_bt::BTDevice::getCreationTimestamp
uint64_t getCreationTimestamp() const noexcept
Returns the timestamp in monotonic milliseconds when this device instance has been created,...
Definition: BTDevice.hpp:253
direct_bt::BTGattService
Representing a complete [Primary] Service Declaration including its list of Characteristic Declaratio...
Definition: BTGattService.hpp:67
direct_bt::ScanType
ScanType
Meta ScanType as derived from BTMode, with defined value mask consisting of BDAddressType bits.
Definition: BTTypes0.hpp:294
direct_bt::BTDevice::toString
std::string toString() const noexcept override
Definition: BTDevice.hpp:303
direct_bt::BTGattChar::addCharListener
bool addCharListener(std::shared_ptr< Listener > l)
Add the given BTGattChar::Listener to the listener list if not already present.
Definition: BTGattChar.cpp:285
direct_bt::BTAdapter::isPowered
bool isPowered() const noexcept
Returns whether the adapter is valid, plugged in and powered.
Definition: BTAdapter.hpp:437
direct_bt::HCIStatusCode
HCIStatusCode
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
Definition: HCITypes.hpp:124
jau::darray< BTGattServiceRef >
direct_bt::BTGattCharRef
std::shared_ptr< BTGattChar > BTGattCharRef
Definition: BTGattChar.hpp:409
direct_bt::BTDevice::getGattGenericAccess
std::shared_ptr< GattGenericAccessSvc > getGattGenericAccess()
Returns the shared GenericAccess instance, retrieved by getGattService() or nullptr if not available.
Definition: BTDevice.cpp:1590
TEMPERATURE_MEASUREMENT
@ TEMPERATURE_MEASUREMENT
Definition: test_datatype02.hpp:82
direct_bt::BTAdapter::toString
std::string toString() const noexcept override
Definition: BTAdapter.hpp:784
direct_bt::BTGattHandler::Defaults::MAX_ATT_MTU
@ MAX_ATT_MTU
mtxDeviceFound
std::mutex mtxDeviceFound
Definition: dbt_scanner00.cpp:52
direct_bt::BTManager::get
static BTManager & get(const BTMode defaultBTMode=BTMode::NONE)
Retrieves the singleton instance.
Definition: BTManager.hpp:320
direct_bt::BTDevice::disconnect
HCIStatusCode disconnect(const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION) noexcept
Disconnect the LE or BREDR peer's GATT and HCI connection.
Definition: BTDevice.cpp:1701
main
int main(int argc, char *argv[])
Definition: dbt_scanner00.cpp:155
direct_bt::BTDevice::ts_creation
const uint64_t ts_creation
Definition: BTDevice.hpp:220
direct_bt::GattDeviceInformationSvc::toString
std::string toString() const noexcept
Definition: GATTNumbers.cpp:407
jau::darray::size
constexpr size_type size() const noexcept
Like std::vector::size().
Definition: darray.hpp:668
Read
@ Read
Definition: test_datatype02.hpp:106
direct_bt::PairingMode
PairingMode
Bluetooth secure pairing mode.
Definition: BTTypes0.hpp:261
MyAdapterStatusListener
Definition: dbt_scanner00.cpp:55
direct_bt::BTManager
A thread safe singleton handler of the Linux Kernel's BlueZ manager control channel.
Definition: BTManager.hpp:201
jau::dfa_utf8_decode
uint32_t dfa_utf8_decode(uint32_t &state, uint32_t &codep, const uint32_t byte_value)
Definition: dfa_utf8_decode.cpp:90
direct_bt::BTAdapter::addStatusListener
bool addStatusListener(std::shared_ptr< AdapterStatusListener > l)
Add the given listener to the list if not already present.
Definition: BTAdapter.cpp:548
direct_bt::BTGattChar::toString
std::string toString() const noexcept override
Definition: BTGattChar.cpp:106
direct_bt::TROOctets
Transient read only octet data, i.e.
Definition: OctetTypes.hpp:59
direct_bt::to_string
std::string to_string(const BDAddressType type) noexcept
Definition: BTTypes0.cpp:129
direct_bt::BTAdapter
BTAdapter represents one Bluetooth Controller.
Definition: BTAdapter.hpp:250
jau::getCurrentMilliseconds
uint64_t getCurrentMilliseconds() noexcept
Returns current monotonic time in milliseconds.
Definition: basic_types.cpp:47
charValue
static int charValue
Definition: dbt_scanner10.cpp:121
direct_bt::EUI48
A packed 48 bit EUI-48 identifier, formerly known as MAC-48 or simply network device MAC address (Med...
Definition: BTAddress.hpp:388
jau::to_hexstring
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
Definition: string_util.hpp:104
direct_bt::BTAdapter::isValid
bool isValid() const noexcept
Returns whether the adapter is valid, i.e.
Definition: BTAdapter.hpp:480
direct_bt::BTGattService::toString
std::string toString() const noexcept override
Definition: BTGattService.cpp:66
direct_bt::BTDevice::getGattServices
jau::darray< std::shared_ptr< BTGattService > > getGattServices() noexcept
Returns a list of shared GATTService available on this device if successful, otherwise returns an emp...
Definition: BTDevice.cpp:1525
direct_bt::BTGattHandler::isConnected
bool isConnected() const noexcept
Definition: BTGattHandler.hpp:253
MyGATTEventListener
Definition: dbt_scanner00.cpp:118
direct_bt::HCIStatusCode::SUCCESS
@ SUCCESS
direct_bt::BTGattChar::configNotificationIndication
bool configNotificationIndication(const bool enableNotification, const bool enableIndication, bool enabledState[2])
BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration.
Definition: BTGattChar.cpp:186
direct_bt::BTDevice::getGattHandler
std::shared_ptr< BTGattHandler > getGattHandler() noexcept
Returns the connected GATTHandler or nullptr, see connectGATT(), getGattService() and disconnect().
Definition: BTDevice.cpp:1520
deviceFound
std::shared_ptr< BTDevice > deviceFound
This C++ direct_bt scanner example is a TinyB backward compatible and not fully event driven.
Definition: dbt_scanner00.cpp:51
cvDeviceFound
std::condition_variable cvDeviceFound
Definition: dbt_scanner00.cpp:53
direct_bt::POctets
Persistent octet data, i.e.
Definition: OctetTypes.hpp:451
direct_bt::BTAdapter::startDiscovery
HCIStatusCode startDiscovery(const bool keepAlive=true, const bool le_scan_active=false, const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24, const uint8_t filter_policy=0x00)
Starts a new discovery session.
Definition: BTAdapter.cpp:679
direct_bt::SMPPairingState
SMPPairingState
SMP Pairing Process state definition.
Definition: SMPTypes.hpp:101
direct_bt::BTGattHandler::number
static constexpr int number(const Defaults d)
Definition: BTGattHandler.hpp:149
direct_bt::BDAddressAndType
Unique Bluetooth EUI48 address and BDAddressType tuple.
Definition: BTAddress.hpp:417
direct_bt::BTManager::getAdapter
std::shared_ptr< BTAdapter > getAdapter(const uint16_t dev_id) const noexcept
Returns the DBTAdapter with the given dev_id, or nullptr if not found.
Definition: BTManager.cpp:624
direct_bt::BTDevice::getAdapter
BTAdapter & getAdapter() const
Returns the managing adapter.
Definition: BTDevice.hpp:243
direct_bt::GattTemperatureMeasurement::toString
std::string toString() const noexcept
Definition: GATTNumbers.cpp:453
direct_bt::BTGattChar::Listener
BTGattChar event listener for notification and indication events.
Definition: BTGattChar.hpp:122
direct_bt::BDAddressType::BDADDR_UNDEFINED
@ BDADDR_UNDEFINED
Undefined.