Direct-BT v3.3.0-1-gc2d430c
Direct-BT - Direct Bluetooth Programming.
dbt_peripheral00.cpp

This _dbt_peripheral00__ C++ peripheral ::BTRole::Slave GATT server example uses an event driven workflow.

This _dbt_peripheral00__ C++ peripheral ::BTRole::Slave GATT server example uses an event driven workflow.

dbt_peripheral00 Invocation Examples:

Using scripts/run-dbt_peripheral00.sh from dist directory:

/*
* Author: Sven Gothel <sgothel@jausoft.com>
* Copyright (c) 2021 Gothel Software e.K.
* Copyright (c) 2021 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 <cstring>
#include <string>
#include <memory>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <cinttypes>
#include <pthread.h>
#include <csignal>
#include <jau/darray.hpp>
extern "C" {
#include <unistd.h>
}
#include "dbt_constants.hpp"
using namespace direct_bt;
using namespace jau;
/** \file
* This _dbt_peripheral00__ C++ peripheral ::BTRole::Slave GATT server example uses an event driven workflow.
*
* ### dbt_peripheral00 Invocation Examples:
* Using `scripts/run-dbt_peripheral00.sh` from `dist` directory:
*
* * Serving clients as `TestDevice001` using adapter 00:1A:7D:DA:71:03; Using ENC_ONLY (JUST_WORKS) encryption.
* ~~~
* ../scripts/run-dbt_peripheral00.sh -adapter 00:1A:7D:DA:71:03 -name TestDevice001 -seclevel 2
* ~~~
*/
static uint64_t timestamp_t0;
static EUI48 useAdapter = EUI48::ALL_DEVICE;
static BTMode btMode = BTMode::DUAL;
static bool use_SC = true;
static std::string adapter_name = "TestDev001_N";
static std::string adapter_short_name = "TDev001N";
static std::shared_ptr<BTAdapter> chosenAdapter = nullptr;
static BTSecurityLevel adapter_sec_level = BTSecurityLevel::UNSET;
static SMPIOCapability adapter_sec_io_cap = SMPIOCapability::UNSET;
static bool SHOW_UPDATE_EVENTS = false;
static bool RUN_ONLY_ONCE = false;
static BTDeviceRef connectedDevice = nullptr;
static bool startAdvertising(BTAdapter *a, std::string msg); // NOLINT(performance-unnecessary-value-param): Pass-by-value out-of-thread
static bool stopAdvertising(BTAdapter *a, std::string msg); // NOLINT(performance-unnecessary-value-param): Pass-by-value out-of-thread
static void processDisconnectedDevice(BTDeviceRef device); // NOLINT(performance-unnecessary-value-param): Pass-by-value out-of-thread
static void setDevice(const BTDeviceRef& cd) {
}
}
static bool matches(const BTDeviceRef& device) {
const BTDeviceRef d = getDevice();
return nullptr != d ? (*d) == *device : false;
}
static const jau::uuid128_t DataServiceUUID = jau::uuid128_t("d0ca6bf3-3d50-4760-98e5-fc5883e93712");
static const jau::uuid128_t StaticDataUUID = jau::uuid128_t("d0ca6bf3-3d51-4760-98e5-fc5883e93712");
static const jau::uuid128_t CommandUUID = jau::uuid128_t("d0ca6bf3-3d52-4760-98e5-fc5883e93712");
static const jau::uuid128_t ResponseUUID = jau::uuid128_t("d0ca6bf3-3d53-4760-98e5-fc5883e93712");
static const jau::uuid128_t PulseDataUUID = jau::uuid128_t("d0ca6bf3-3d54-4760-98e5-fc5883e93712");
// DBGattServerRef dbGattServer = std::make_shared<DBGattServer>(
/* services: */
jau::make_darray( // DBGattService
std::make_shared<DBGattService> ( true /* primary */,
std::make_unique<const jau::uuid16_t>(GattServiceType::GENERIC_ACCESS) /* type_ */,
jau::make_darray ( // DBGattChar
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::DEVICE_NAME) /* value_type_ */,
jau::darray<DBGattDescRef>() /* intentionally empty */,
make_gvalue(adapter_name.c_str(), 128) /* value */, true /* variable_length */ ),
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::APPEARANCE) /* value_type_ */,
jau::darray<DBGattDescRef>() /* intentionally empty */,
make_gvalue((uint16_t)0) /* value */ )
) ),
std::make_shared<DBGattService> ( true /* primary */,
std::make_unique<const jau::uuid16_t>(GattServiceType::DEVICE_INFORMATION) /* type_ */,
jau::make_darray ( // DBGattChar
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::MANUFACTURER_NAME_STRING) /* value_type_ */,
jau::darray<DBGattDescRef>() /* intentionally empty */,
make_gvalue("Gothel Software") /* value */ ),
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::MODEL_NUMBER_STRING) /* value_type_ */,
jau::darray<DBGattDescRef>() /* intentionally empty */,
make_gvalue("2.4.0-pre") /* value */ ),
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::SERIAL_NUMBER_STRING) /* value_type_ */,
jau::darray<DBGattDescRef>() /* intentionally empty */,
make_gvalue("sn:0123456789") /* value */ ),
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::HARDWARE_REVISION_STRING) /* value_type_ */,
jau::darray<DBGattDescRef>() /* intentionally empty */,
make_gvalue("hw:0123456789") /* value */ ),
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::FIRMWARE_REVISION_STRING) /* value_type_ */,
jau::darray<DBGattDescRef>() /* intentionally empty */,
make_gvalue("fw:0123456789") /* value */ ),
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid16_t>(GattCharacteristicType::SOFTWARE_REVISION_STRING) /* value_type_ */,
jau::darray<DBGattDescRef>() /* intentionally empty */,
make_gvalue("sw:0123456789") /* value */ )
) ),
std::make_shared<DBGattService> ( true /* primary */,
std::make_unique<const jau::uuid128_t>(DataServiceUUID) /* type_ */,
jau::make_darray ( // DBGattChar
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid128_t>(StaticDataUUID) /* value_type_ */,
jau::make_darray ( // DBGattDesc
std::make_shared<DBGattDesc>( BTGattDesc::TYPE_USER_DESC, make_gvalue("DATA_STATIC") )
),
make_gvalue("Proprietary Static Data 0x00010203") /* value */ ),
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid128_t>(CommandUUID) /* value_type_ */,
jau::make_darray ( // DBGattDesc
std::make_shared<DBGattDesc>( BTGattDesc::TYPE_USER_DESC, make_gvalue("COMMAND") )
),
make_gvalue(128, 64) /* value */, true /* variable_length */ ),
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid128_t>(ResponseUUID) /* value_type_ */,
jau::make_darray ( // DBGattDesc
std::make_shared<DBGattDesc>( BTGattDesc::TYPE_USER_DESC, make_gvalue("RESPONSE") ),
DBGattDesc::createClientCharConfig()
),
make_gvalue((uint16_t)0) /* value */ ),
std::make_shared<DBGattChar>( std::make_unique<const jau::uuid128_t>(PulseDataUUID) /* value_type_ */,
jau::make_darray ( // DBGattDesc
std::make_shared<DBGattDesc>( BTGattDesc::TYPE_USER_DESC, make_gvalue("DATA_PULSE") ),
DBGattDesc::createClientCharConfig()
),
make_gvalue("Synthethic Sensor 01") /* value */ )
) )
) ) );
void adapterSettingsChanged(BTAdapter &a, const AdapterSetting oldmask, const AdapterSetting newmask,
const AdapterSetting changedmask, const uint64_t timestamp) override {
const bool initialSetting = AdapterSetting::NONE == oldmask;
if( initialSetting ) {
fprintf_td(stderr, "****** SETTINGS_INITIAL: %s -> %s, changed %s\n", to_string(oldmask).c_str(),
to_string(newmask).c_str(), to_string(changedmask).c_str());
} else {
fprintf_td(stderr, "****** SETTINGS_CHANGED: %s -> %s, changed %s\n", to_string(oldmask).c_str(),
to_string(newmask).c_str(), to_string(changedmask).c_str());
}
fprintf_td(stderr, "Status BTAdapter:\n");
fprintf_td(stderr, "%s\n", a.toString().c_str());
(void)timestamp;
if( !initialSetting &&
isAdapterSettingBitSet(changedmask, AdapterSetting::POWERED) &&
isAdapterSettingBitSet(newmask, AdapterSetting::POWERED) )
{
std::thread sd(::startAdvertising, &a, "powered-on"); // @suppress("Invalid arguments")
sd.detach();
}
}
void discoveringChanged(BTAdapter &a, const ScanType currentMeta, const ScanType changedType, const bool changedEnabled, const DiscoveryPolicy policy, const uint64_t timestamp) override {
fprintf_td(stderr, "****** DISCOVERING: meta %s, changed[%s, enabled %d, policy %s]: %s\n",
to_string(currentMeta).c_str(), to_string(changedType).c_str(), changedEnabled, to_string(policy).c_str(), a.toString().c_str());
(void)timestamp;
}
bool deviceFound(const BTDeviceRef& device, const uint64_t timestamp) override {
(void)timestamp;
fprintf_td(stderr, "****** FOUND__-1: NOP %s\n", device->toString(true).c_str());
return false;
}
void deviceUpdated(const BTDeviceRef& device, const EIRDataType updateMask, const uint64_t timestamp) override {
if( is_set(updateMask, EIRDataType::BDADDR)) {
fprintf_td(stderr, "****** UPDATED (ADDR-RESOLVED): %s of %s\n", to_string(updateMask).c_str(), device->toString(true).c_str());
} else if( SHOW_UPDATE_EVENTS ) {
fprintf_td(stderr, "****** UPDATED: %s of %s\n", to_string(updateMask).c_str(), device->toString(true).c_str());
}
(void)timestamp;
}
void deviceConnected(const BTDeviceRef& device, const bool discovered, const uint64_t timestamp) override {
fprintf_td(stderr, "****** CONNECTED (discovered %d): %s\n", discovered, device->toString(true).c_str());
const bool available = nullptr == getDevice();
if( available ) {
setDevice(device);
}
(void)discovered;
(void)timestamp;
}
void devicePairingState(const BTDeviceRef& device, const SMPPairingState state, const PairingMode mode, const uint64_t timestamp) override {
fprintf_td(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;
switch( state ) {
case SMPPairingState::NONE:
// next: deviceReady(..)
break;
case SMPPairingState::FAILED: {
// next: deviceReady() or deviceDisconnected(..)
} break;
case SMPPairingState::REQUESTED_BY_RESPONDER:
// next: FEATURE_EXCHANGE_STARTED
break;
case SMPPairingState::FEATURE_EXCHANGE_STARTED:
// next: FEATURE_EXCHANGE_COMPLETED
break;
case SMPPairingState::FEATURE_EXCHANGE_COMPLETED:
// next: PASSKEY_EXPECTED... or KEY_DISTRIBUTION
break;
case SMPPairingState::PASSKEY_EXPECTED: {
const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getStartOf(device->getAddressAndType().address, "");
if( nullptr != sec && sec->getPairingPasskey() != BTSecurityRegistry::Entry::NO_PASSKEY ) {
std::thread dc(&BTDevice::setPairingPasskey, device, static_cast<uint32_t>( sec->getPairingPasskey() ));
dc.detach();
} else {
std::thread dc(&BTDevice::setPairingPasskey, device, 0);
// 3s disconnect: std::thread dc(&BTDevice::setPairingPasskeyNegative, device);
dc.detach();
}
// next: KEY_DISTRIBUTION or FAILED
} break;
case SMPPairingState::NUMERIC_COMPARE_EXPECTED: {
const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getStartOf(device->getAddressAndType().address, "");
if( nullptr != sec ) {
std::thread dc(&BTDevice::setPairingNumericComparison, device, sec->getPairingNumericComparison());
dc.detach();
} else {
std::thread dc(&BTDevice::setPairingNumericComparison, device, true); // FIXME
dc.detach();
}
// next: KEY_DISTRIBUTION or FAILED
} break;
case SMPPairingState::PASSKEY_NOTIFY: {
fprintf_td(stderr, "****** \n");
fprintf_td(stderr, "****** \n");
fprintf_td(stderr, "****** Confirm on your device %s\n", device->getName().c_str());
fprintf_td(stderr, "****** PassKey: %s\n", device->getResponderSMPPassKeyString().c_str());
fprintf_td(stderr, "****** \n");
fprintf_td(stderr, "****** \n");
// next: KEY_DISTRIBUTION or FAILED
} break;
case SMPPairingState::OOB_EXPECTED:
// FIXME: ABORT
break;
case SMPPairingState::KEY_DISTRIBUTION:
// next: COMPLETED or FAILED
break;
case SMPPairingState::COMPLETED:
// next: deviceReady(..)
break;
default: // nop
break;
}
}
void deviceReady(const BTDeviceRef& device, const uint64_t timestamp) override {
(void)timestamp;
fprintf_td(stderr, "****** READY-1: NOP %s\n", device->toString(true).c_str());
}
void deviceDisconnected(const BTDeviceRef& device, const HCIStatusCode reason, const uint16_t handle, const uint64_t timestamp) override {
fprintf_td(stderr, "****** DISCONNECTED (count %zu): Reason 0x%X (%s), old handle %s: %s\n",
servedConnections.load(), static_cast<uint8_t>(reason), to_string(reason).c_str(),
to_hexstring(handle).c_str(), device->toString(true).c_str());
const bool match = matches(device);
if( match ) {
setDevice(nullptr);
}
std::thread sd(::processDisconnectedDevice, device); // @suppress("Invalid arguments")
sd.detach();
(void)timestamp;
}
std::string toString() const noexcept override {
return "MyAdapterStatusListener[this "+to_hexstring(this)+"]";
}
};
private:
jau::service_runner pulse_service;
jau::sc_atomic_uint16 handlePulseDataNotify = 0;
jau::sc_atomic_uint16 handlePulseDataIndicate = 0;
jau::sc_atomic_uint16 handleResponseDataNotify = 0;
jau::sc_atomic_uint16 handleResponseDataIndicate = 0;
uint16_t usedMTU = BTGattHandler::number(BTGattHandler::Defaults::MIN_ATT_MTU);
void clear() {
handlePulseDataNotify = 0;
handlePulseDataIndicate = 0;
handleResponseDataNotify = 0;
handleResponseDataIndicate = 0;
dbGattServer->resetGattClientCharConfig(DataServiceUUID, PulseDataUUID);
dbGattServer->resetGattClientCharConfig(DataServiceUUID, ResponseUUID);
}
void pulse_worker_init(jau::service_runner& sr) noexcept {
(void)sr;
const BTDeviceRef connectedDevice_ = getDevice();
const std::string connectedDeviceStr = nullptr != connectedDevice_ ? connectedDevice_->toString() : "n/a";
fprintf_td(stderr, "****** Server GATT::PULSE Start %s\n", connectedDeviceStr.c_str());
}
void pulse_worker(jau::service_runner& sr) noexcept {
BTDeviceRef connectedDevice_ = getDevice();
if( nullptr != connectedDevice_ && connectedDevice_->getConnected() ) {
if( 0 != handlePulseDataNotify || 0 != handlePulseDataIndicate ) {
std::string data( "Dynamic Data Example. Elapsed Milliseconds: "+jau::to_decstring(environment::getElapsedMillisecond(), ',', 9) );
jau::POctets v(data.size()+1, jau::lb_endian::little);
v.put_string_nc(0, data, v.size(), true /* includeEOS */);
if( 0 != handlePulseDataNotify ) {
const bool res = connectedDevice_->sendNotification(handlePulseDataNotify, v);
fprintf_td(stderr, "****** GATT::sendNotification: PULSE (res %d) to %s\n", res, connectedDevice_->toString().c_str());
}
if( 0 != handlePulseDataIndicate ) {
const bool res = connectedDevice_->sendIndication(handlePulseDataIndicate, v);
fprintf_td(stderr, "****** GATT::sendIndication: PULSE (res %d) to %s\n", res, connectedDevice_->toString().c_str());
}
}
}
if( !sr.shall_stop() ) {
jau::sleep_for( 500_ms );
}
}
void pulse_worker_end(jau::service_runner& sr) noexcept {
(void)sr;
const BTDeviceRef connectedDevice_ = getDevice();
const std::string connectedDeviceStr = nullptr != connectedDevice_ ? connectedDevice_->toString() : "n/a";
fprintf_td(stderr, "****** Server GATT::PULSE End %s\n", connectedDeviceStr.c_str());
}
void sendResponse(jau::POctets data) { // NOLINT(performance-unnecessary-value-param): Pass-by-value out-of-thread
BTDeviceRef connectedDevice_ = getDevice();
if( nullptr != connectedDevice_ && connectedDevice_->getConnected() ) {
if( 0 != handleResponseDataNotify || 0 != handleResponseDataIndicate ) {
if( 0 != handleResponseDataNotify ) {
const bool res = connectedDevice_->sendNotification(handleResponseDataNotify, data);
fprintf_td(stderr, "****** GATT::sendNotification (res %d): %s to %s\n",
res, data.toString().c_str(), connectedDevice_->toString().c_str());
}
if( 0 != handleResponseDataIndicate ) {
const bool res = connectedDevice_->sendIndication(handleResponseDataIndicate, data);
fprintf_td(stderr, "****** GATT::sendIndication (res %d): %s to %s\n",
res, data.toString().c_str(), connectedDevice_->toString().c_str());
}
}
}
}
public:
: pulse_service("MyGATTServerListener::pulse", THREAD_SHUTDOWN_TIMEOUT_MS,
jau::bind_member(this, &MyGATTServerListener::pulse_worker),
jau::bind_member(this, &MyGATTServerListener::pulse_worker_init),
jau::bind_member(this, &MyGATTServerListener::pulse_worker_end))
{
pulse_service.start();
}
~MyGATTServerListener() noexcept override {
pulse_service.stop();
}
void close() noexcept {
pulse_service.stop();
clear();
}
void connected(const BTDeviceRef& device, const uint16_t initialMTU) override {
const bool match = matches(device);
fprintf_td(stderr, "****** GATT::connected(match %d): initMTU %d, %s\n",
match, (int)initialMTU, device->toString().c_str());
if( match ) {
usedMTU = initialMTU;
}
}
void disconnected(const BTDeviceRef& device) override {
const bool match = matches(device);
fprintf_td(stderr, "****** GATT::disconnected(match %d): %s\n", match, device->toString().c_str());
if( match ) {
clear();
}
}
void mtuChanged(const BTDeviceRef& device, const uint16_t mtu) override {
const bool match = matches(device);
fprintf_td(stderr, "****** GATT::mtuChanged(match %d): %d -> %d, %s\n",
match, match ? (int)usedMTU : 0, (int)mtu, device->toString().c_str());
if( match ) {
usedMTU = mtu;
}
}
bool readCharValue(const BTDeviceRef& device, const DBGattServiceRef& s, const DBGattCharRef& c) override {
const bool match = matches(device);
fprintf_td(stderr, "****** GATT::readCharValue(match %d): to %s, from\n %s\n %s\n",
match, device->toString().c_str(), s->toString().c_str(), c->toString().c_str());
return match;
}
bool readDescValue(const BTDeviceRef& device, const DBGattServiceRef& s, const DBGattCharRef& c, const DBGattDescRef& d) override {
const bool match = matches(device);
fprintf_td(stderr, "****** GATT::readDescValue(match %d): to %s, from\n %s\n %s\n %s\n",
match, device->toString().c_str(), s->toString().c_str(), c->toString().c_str(), d->toString().c_str());
return match;
}
bool writeCharValue(const BTDeviceRef& device, const DBGattServiceRef& s, const DBGattCharRef& c, const jau::TROOctets & value, const uint16_t value_offset) override {
const bool match = matches(device);
fprintf_td(stderr, "****** GATT::writeCharValue(match %d): %s '%s' @ %u from %s, to\n %s\n %s\n",
match, value.toString().c_str(), jau::dfa_utf8_decode( value.get_ptr(), value.size() ).c_str(),
value_offset,
device->toString().c_str(), s->toString().c_str(), c->toString().c_str());
return match;
}
void writeCharValueDone(const BTDeviceRef& device, const DBGattServiceRef& s, const DBGattCharRef& c) override {
const bool match = matches(device);
const jau::TROOctets& value = c->getValue();
fprintf_td(stderr, "****** GATT::writeCharValueDone(match %d): From %s, to\n %s\n %s\n Char-Value: %s\n",
match, device->toString().c_str(), s->toString().c_str(), c->toString().c_str(), value.toString().c_str());
if( match &&
c->getValueType()->equivalent( CommandUUID ) &&
( 0 != handleResponseDataNotify || 0 != handleResponseDataIndicate ) )
{
jau::POctets value2(value);
std::thread senderThread(&MyGATTServerListener::sendResponse, this, value2); // @suppress("Invalid arguments")
senderThread.detach();
}
}
bool writeDescValue(const BTDeviceRef& device, const DBGattServiceRef& s, const DBGattCharRef& c, const DBGattDescRef& d, const jau::TROOctets & value, const uint16_t value_offset) override {
const bool match = matches(device);
fprintf_td(stderr, "****** GATT::writeDescValue(match %d): %s '%s' @ %u from %s\n %s\n %s\n %s\n",
match, value.toString().c_str(), jau::dfa_utf8_decode( value.get_ptr(), value.size() ).c_str(),
value_offset,
device->toString().c_str(), s->toString().c_str(), c->toString().c_str(), d->toString().c_str());
return match;
}
void writeDescValueDone(const BTDeviceRef& device, const DBGattServiceRef& s, const DBGattCharRef& c, const DBGattDescRef& d) override {
const bool match = matches(device);
const jau::TROOctets& value = d->getValue();
fprintf_td(stderr, "****** GATT::writeDescValueDone(match %d): From %s\n %s\n %s\n %s\n Desc-Value: %s\n",
match, device->toString().c_str(), s->toString().c_str(), c->toString().c_str(), d->toString().c_str(), value.toString().c_str());
}
void clientCharConfigChanged(const BTDeviceRef& device, const DBGattServiceRef& s, const DBGattCharRef& c, const DBGattDescRef& d, const bool notificationEnabled, const bool indicationEnabled) override {
const bool match = matches(device);
const jau::TROOctets& value = d->getValue();
fprintf_td(stderr, "****** GATT::clientCharConfigChanged(match %d): notify %d, indicate %d from %s\n %s\n %s\n %s\n Desc-Value: %s\n",
match, notificationEnabled, indicationEnabled,
device->toString().c_str(), s->toString().c_str(), c->toString().c_str(), d->toString().c_str(), value.toString().c_str());
if( match ) {
if( c->getValueType()->equivalent( PulseDataUUID ) ) {
handlePulseDataNotify = notificationEnabled ? c->getValueHandle() : 0;
handlePulseDataIndicate = indicationEnabled ? c->getValueHandle() : 0;
} else if( c->getValueType()->equivalent( ResponseUUID ) ) {
handleResponseDataNotify = notificationEnabled ? c->getValueHandle() : 0;
handleResponseDataIndicate = indicationEnabled ? c->getValueHandle() : 0;
}
}
}
};
static const uint16_t adv_interval_min=160; // x0.625 = 100ms
static const uint16_t adv_interval_max=480; // x0.625 = 300ms
static const AD_PDU_Type adv_type=AD_PDU_Type::ADV_IND;
static const uint8_t adv_chan_map=0x07;
static const uint8_t filter_policy=0x00;
static bool startAdvertising(BTAdapter *a, std::string msg) { // NOLINT(performance-unnecessary-value-param): Pass-by-value out-of-thread
if( useAdapter != EUI48::ALL_DEVICE && useAdapter != a->getAddressAndType().address ) {
fprintf_td(stderr, "****** Start advertising (%s): Adapter not selected: %s\n", msg.c_str(), a->toString().c_str());
return false;
}
{
const LE_Features le_feats = a->getLEFeatures();
fprintf_td(stderr, "startAdvertising: LE_Features %s\n", to_string(le_feats).c_str());
}
if( a->getBTMajorVersion() > 4 ) {
LE_PHYs Tx { LE_PHYs::LE_2M }, Rx { LE_PHYs::LE_2M };
HCIStatusCode res = a->setDefaultLE_PHY(Tx, Rx);
fprintf_td(stderr, "startAdvertising: Set Default LE PHY: status %s: Tx %s, Rx %s\n",
to_string(res).c_str(), to_string(Tx).c_str(), to_string(Rx).c_str());
}
EIRDataType adv_mask = EIRDataType::FLAGS | EIRDataType::SERVICE_UUID;
EIRDataType scanrsp_mask = EIRDataType::NAME | EIRDataType::CONN_IVAL;
eir.addFlags(GAPFlags::LE_Gen_Disc);
eir.addFlags(GAPFlags::BREDR_UNSUP);
eir.setServicesComplete(false);
eir.setName(a->getName());
eir.setConnInterval(8, 12); // 10ms - 15ms
if( nullptr != gattDevNameChar ) {
std::string aname = a->getName();
gattDevNameChar->setValue(reinterpret_cast<uint8_t*>(aname.data()), aname.size(), 0);
}
fprintf_td(stderr, "****** Start advertising (%s): EIR %s\n", msg.c_str(), eir.toString().c_str());
fprintf_td(stderr, "****** Start advertising (%s): adv %s, scanrsp %s\n", msg.c_str(), to_string(adv_mask).c_str(), to_string(scanrsp_mask).c_str());
HCIStatusCode status = a->startAdvertising(dbGattServer, eir, adv_mask, scanrsp_mask,
fprintf_td(stderr, "****** Start advertising (%s) result: %s: %s\n", msg.c_str(), to_string(status).c_str(), a->toString().c_str());
fprintf_td(stderr, "%s", dbGattServer->toFullString().c_str());
return HCIStatusCode::SUCCESS == status;
}
static bool stopAdvertising(BTAdapter *a, std::string msg) { // NOLINT(performance-unnecessary-value-param): Pass-by-value out-of-thread
if( useAdapter != EUI48::ALL_DEVICE && useAdapter != a->getAddressAndType().address ) {
fprintf_td(stderr, "****** Stop advertising (%s): Adapter not selected: %s\n", msg.c_str(), a->toString().c_str());
return false;
}
fprintf_td(stderr, "****** Stop advertising (%s) result: %s: %s\n", msg.c_str(), to_string(status).c_str(), a->toString().c_str());
return HCIStatusCode::SUCCESS == status;
}
static void processDisconnectedDevice(BTDeviceRef device) { // NOLINT(performance-unnecessary-value-param): Pass-by-value out-of-thread
fprintf_td(stderr, "****** Disconnected Device (count %zu): Start %s\n",
servedConnections.load(), device->toString().c_str());
// already unpaired
stopAdvertising(&device->getAdapter(), "device-disconnected");
device->remove();
jau::sleep_for( 100_ms ); // wait a little (FIXME: Fast restart of advertising error)
if( !RUN_ONLY_ONCE ) {
startAdvertising(&device->getAdapter(), "device-disconnected");
}
fprintf_td(stderr, "****** Disonnected Device: End %s\n", device->toString().c_str());
}
static bool initAdapter(std::shared_ptr<BTAdapter>& adapter) {
if( useAdapter != EUI48::ALL_DEVICE && useAdapter != adapter->getAddressAndType().address ) {
fprintf_td(stderr, "initAdapter: Adapter not selected: %s\n", adapter->toString().c_str());
return false;
}
if( !adapter->isInitialized() ) {
// Initialize with defaults and power-on
const HCIStatusCode status = adapter->initialize( btMode, false );
if( HCIStatusCode::SUCCESS != status ) {
fprintf_td(stderr, "initAdapter: initialize failed: %s: %s\n",
to_string(status).c_str(), adapter->toString().c_str());
return false;
}
} else if( !adapter->setPowered( false ) ) {
fprintf_td(stderr, "initAdapter: setPower.1 off failed: %s\n", adapter->toString().c_str());
return false;
}
// adapter is powered-off
fprintf_td(stderr, "initAdapter.1: %s\n", adapter->toString().c_str());
{
HCIStatusCode status = adapter->setName(adapter_name, adapter_short_name);
if( HCIStatusCode::SUCCESS == status ) {
fprintf_td(stderr, "initAdapter: setLocalName OK: %s\n", adapter->toString().c_str());
} else {
fprintf_td(stderr, "initAdapter: setLocalName failed: %s\n", adapter->toString().c_str());
return false;
}
status = adapter->setSecureConnections( use_SC );
if( HCIStatusCode::SUCCESS == status ) {
fprintf_td(stderr, "initAdapter: setSecureConnections OK: %s\n", adapter->toString().c_str());
} else {
fprintf_td(stderr, "initAdapter: setSecureConnections failed: %s\n", adapter->toString().c_str());
return false;
}
const uint16_t conn_min_interval = 8; // 10ms
const uint16_t conn_max_interval = 40; // 50ms
const uint16_t conn_latency = 0;
const uint16_t supervision_timeout = 50; // 500ms
status = adapter->setDefaultConnParam(conn_min_interval, conn_max_interval, conn_latency, supervision_timeout);
if( HCIStatusCode::SUCCESS == status ) {
fprintf_td(stderr, "initAdapter: setDefaultConnParam OK: %s\n", adapter->toString().c_str());
} else if( HCIStatusCode::UNKNOWN_COMMAND == status ) {
fprintf_td(stderr, "initAdapter: setDefaultConnParam UNKNOWN_COMMAND (ignored): %s\n", adapter->toString().c_str());
} else {
fprintf_td(stderr, "initAdapter: setDefaultConnParam failed: %s, %s\n", to_string(status).c_str(), adapter->toString().c_str());
return false;
}
if( !adapter->setPowered( true ) ) {
fprintf_td(stderr, "initAdapter: setPower.2 on failed: %s\n", adapter->toString().c_str());
return false;
}
}
fprintf_td(stderr, "initAdapter.2: %s\n", adapter->toString().c_str());
adapter->setSMPKeyPath(SERVER_KEY_PATH);
std::shared_ptr<AdapterStatusListener> asl( std::make_shared<MyAdapterStatusListener>() );
adapter->addStatusListener( asl );
if( !startAdvertising(adapter.get(), "initAdapter") ) {
adapter->removeStatusListener( asl );
return false;
}
return true;
}
static void myChangedAdapterSetFunc(const bool added, std::shared_ptr<BTAdapter>& adapter) {
if( added ) {
if( nullptr == chosenAdapter ) {
if( initAdapter( adapter ) ) {
chosenAdapter = adapter;
fprintf_td(stderr, "****** Adapter ADDED__: InitOK: %s\n", adapter->toString().c_str());
} else {
fprintf_td(stderr, "****** Adapter ADDED__: Ignored: %s\n", adapter->toString().c_str());
}
fprintf_td(stderr, "****** Adapter Features: %s\n", direct_bt::to_string(adapter->getLEFeatures()).c_str());
} else {
fprintf_td(stderr, "****** Adapter ADDED__: Ignored (other): %s\n", adapter->toString().c_str());
}
} else {
if( nullptr != chosenAdapter && adapter == chosenAdapter ) {
chosenAdapter = nullptr;
fprintf_td(stderr, "****** Adapter REMOVED: %s\n", adapter->toString().c_str());
} else {
fprintf_td(stderr, "****** Adapter REMOVED (other): %s\n", adapter->toString().c_str());
}
}
}
void test() {
std::shared_ptr<BTManager> mngr = BTManager::get();
fprintf_td(stderr, "****** Test Start\n");
std::shared_ptr<MyGATTServerListener> listener = std::make_shared<MyGATTServerListener>();
dbGattServer->addListener( listener );
mngr->addChangedAdapterSetCallback(myChangedAdapterSetFunc);
while( !RUN_ONLY_ONCE || 0 == servedConnections ) {
}
fprintf_td(stderr, "****** Test Shutdown.01 (DBGattServer.remove-listener)\n");
dbGattServer->removeListener( listener );
fprintf_td(stderr, "****** Test Shutdown.02 (listener.close)\n");
listener->close();
fprintf_td(stderr, "****** Test Shutdown.03 (DBGattServer.close := nullptr)\n");
dbGattServer = nullptr;
chosenAdapter = nullptr;
fprintf_td(stderr, "****** Test End\n");
}
#include <cstdio>
int main(int argc, char *argv[])
{
bool waitForEnter=false;
fprintf_td(stderr, "Direct-BT Native Version %s (API %s)\n", DIRECT_BT_VERSION, DIRECT_BT_VERSION_API);
for(int i=1; i<argc; i++) {
if( !strcmp("-dbt_debug", argv[i]) && argc > (i+1) ) {
setenv("direct_bt.debug", argv[++i], 1 /* overwrite */);
} else if( !strcmp("-dbt_verbose", argv[i]) && argc > (i+1) ) {
setenv("direct_bt.verbose", argv[++i], 1 /* overwrite */);
} else if( !strcmp("-dbt_gatt", argv[i]) && argc > (i+1) ) {
setenv("direct_bt.gatt", argv[++i], 1 /* overwrite */);
} else if( !strcmp("-dbt_l2cap", argv[i]) && argc > (i+1) ) {
setenv("direct_bt.l2cap", argv[++i], 1 /* overwrite */);
} else if( !strcmp("-dbt_hci", argv[i]) && argc > (i+1) ) {
setenv("direct_bt.hci", argv[++i], 1 /* overwrite */);
} else if( !strcmp("-dbt_mgmt", argv[i]) && argc > (i+1) ) {
setenv("direct_bt.mgmt", argv[++i], 1 /* overwrite */);
} else if( !strcmp("-wait", argv[i]) ) {
waitForEnter = true;
} else if( !strcmp("-show_update_events", argv[i]) ) {
} else if( !strcmp("-btmode", argv[i]) && argc > (i+1) ) {
btMode = to_BTMode(argv[++i]);
} else if( !strcmp("-use_sc", argv[i]) && argc > (i+1) ) {
use_SC = 0 != atoi(argv[++i]);
} else if( !strcmp("-adapter", argv[i]) && argc > (i+1) ) {
useAdapter = EUI48( std::string(argv[++i]) );
} else if( !strcmp("-name", argv[i]) && argc > (i+1) ) {
adapter_name = std::string(argv[++i]);
} else if( !strcmp("-short_name", argv[i]) && argc > (i+1) ) {
adapter_short_name = std::string(argv[++i]);
} else if( !strcmp("-mtu", argv[i]) && argc > (i+1) ) {
dbGattServer->setMaxAttMTU( atoi(argv[++i]) );
} else if( !strcmp("-seclevel", argv[i]) && argc > (i+1) ) {
} else if( !strcmp("-iocap", argv[i]) && argc > (i+1) ) {
} else if( !strcmp("-once", argv[i]) ) {
RUN_ONLY_ONCE = true;
}
}
fprintf_td(stderr, "pid %d\n", getpid());
fprintf_td(stderr, "Run with '[-btmode LE|BREDR|DUAL] [-use_sc 0|1] "
"[-adapter <adapter_address>] "
"[-name <adapter_name>] "
"[-short_name <adapter_short_name>] "
"[-mtu <max att_mtu>] "
"[-seclevel <int_sec_level>]* "
"[-iocap <int_iocap>]* "
"[-once] "
"[-dbt_verbose true|false] "
"[-dbt_debug true|false|adapter.event,gatt.data,hci.event,hci.scan_ad_eir,mgmt.event] "
"[-dbt_mgmt cmd.timeout=3000,ringsize=64,...] "
"[-dbt_hci cmd.complete.timeout=10000,cmd.status.timeout=3000,ringsize=64,...] "
"[-dbt_gatt cmd.read.timeout=500,cmd.write.timeout=500,cmd.init.timeout=2500,ringsize=128,...] "
"[-dbt_l2cap reader.timeout=10000,restart.count=0,...] "
"\n");
fprintf_td(stderr, "SHOW_UPDATE_EVENTS %d\n", SHOW_UPDATE_EVENTS);
fprintf_td(stderr, "adapter %s\n", useAdapter.toString().c_str());
fprintf_td(stderr, "adapter btmode %s\n", to_string(btMode).c_str());
fprintf_td(stderr, "adapter SC %s\n", to_string(use_SC).c_str());
fprintf_td(stderr, "adapter name %s (short %s)\n", adapter_name.c_str(), adapter_short_name.c_str());
fprintf_td(stderr, "adapter mtu %d\n", (int)dbGattServer->getMaxAttMTU());
fprintf_td(stderr, "adapter sec_level %s\n", to_string(adapter_sec_level).c_str());
fprintf_td(stderr, "adapter io_cap %s\n", to_string(adapter_sec_io_cap).c_str());
fprintf_td(stderr, "once %d\n", (int)RUN_ONLY_ONCE);
fprintf_td(stderr, "GattServer %s\n", dbGattServer->toString().c_str());
fprintf_td(stderr, "GattServer.services: %s\n", dbGattServer->getServices().get_info().c_str());
fprintf_td(stderr, "GattService.characteristics: %s\n", dbGattServer->getServices()[0]->getCharacteristics().get_info().c_str());
if( waitForEnter ) {
fprintf_td(stderr, "Press ENTER to continue\n");
getchar();
}
fprintf_td(stderr, "****** TEST start\n");
test();
fprintf_td(stderr, "****** TEST end\n");
}
void writeDescValueDone(const BTDeviceRef &device, const DBGattServiceRef &s, const DBGattCharRef &c, const DBGattDescRef &d) override
Notifies completion of single or bulk writeCharValue() after having accepted and performed all write ...
void disconnected(const BTDeviceRef &device) override
Notification that device got disconnected.
bool writeDescValue(const BTDeviceRef &device, const DBGattServiceRef &s, const DBGattCharRef &c, const DBGattDescRef &d, const jau::TROOctets &value, const uint16_t value_offset) override
Signals attempt to write a single or bulk (prepare) value.
void writeCharValueDone(const BTDeviceRef &device, const DBGattServiceRef &s, const DBGattCharRef &c) override
Notifies completion of single or bulk writeCharValue() after having accepted and performed all write ...
void connected(const BTDeviceRef &device, const uint16_t initialMTU) override
Notification that device got connected.
void clientCharConfigChanged(const BTDeviceRef &device, const DBGattServiceRef &s, const DBGattCharRef &c, const DBGattDescRef &d, const bool notificationEnabled, const bool indicationEnabled) override
Notifies a change of the Client Characteristic Configuration Descriptor (CCCD) value.
bool readDescValue(const BTDeviceRef &device, const DBGattServiceRef &s, const DBGattCharRef &c, const DBGattDescRef &d) override
Signals attempt to read a value.
bool writeCharValue(const BTDeviceRef &device, const DBGattServiceRef &s, const DBGattCharRef &c, const jau::TROOctets &value, const uint16_t value_offset) override
Signals attempt to write a single or bulk (prepare) value.
void mtuChanged(const BTDeviceRef &device, const uint16_t mtu) override
Notification that the MTU has changed.
~MyGATTServerListener() noexcept override
bool readCharValue(const BTDeviceRef &device, const DBGattServiceRef &s, const DBGattCharRef &c) override
Signals attempt to read a value.
BTAdapter status listener for remote BTDevice discovery events: Added, updated and removed; as well a...
Definition: BTAdapter.hpp:127
BTAdapter represents one local Bluetooth Controller.
Definition: BTAdapter.hpp:324
HCIStatusCode stopAdvertising() noexcept
Ends advertising.
Definition: BTAdapter.cpp:1671
constexpr LE_Features getLEFeatures() const noexcept
Return LE_Features for this controller.
Definition: BTAdapter.hpp:654
std::string toString() const noexcept override
Definition: BTAdapter.hpp:1331
void setServerConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap) noexcept
Sets the given BTSecurityLevel and SMPIOCapability for connecting device when in server (peripheral) ...
Definition: BTAdapter.cpp:735
HCIStatusCode startAdvertising(const DBGattServerRef &gattServerData_, EInfoReport &eir, EIRDataType adv_mask=EIRDataType::FLAGS|EIRDataType::SERVICE_UUID, EIRDataType scanrsp_mask=EIRDataType::NAME|EIRDataType::CONN_IVAL, const uint16_t adv_interval_min=160, const uint16_t adv_interval_max=480, const AD_PDU_Type adv_type=AD_PDU_Type::ADV_IND, const uint8_t adv_chan_map=0x07, const uint8_t filter_policy=0x00) noexcept
Starts advertising.
Definition: BTAdapter.cpp:1557
BDAddressAndType const & getAddressAndType() const noexcept
Returns the adapter's public BDAddressAndType, i.e.
Definition: BTAdapter.hpp:691
HCIStatusCode setDefaultLE_PHY(const LE_PHYs Tx, const LE_PHYs Rx) noexcept
Sets default preference of LE_PHYs.
Definition: BTAdapter.cpp:978
constexpr uint16_t getBTMajorVersion() const noexcept
Returns the Bluetooth major version of this adapter.
Definition: BTAdapter.hpp:657
std::string getName() const noexcept
Returns the name.
Definition: BTAdapter.hpp:714
Listener to remote master device's operations on the local GATT-Server.
Representing a complete list of Gatt Service objects from the GATTRole::Server perspective,...
Collection of 'Extended Advertising Data' (EAD), 'Advertising Data' (AD) or 'Extended Inquiry Respons...
Definition: BTTypes0.hpp:898
std::string toString(const bool includeServices=true) const noexcept
Definition: BTTypes0.cpp:854
void setServicesComplete(const bool v) noexcept
Definition: BTTypes0.hpp:999
void addFlags(GAPFlags f) noexcept
Definition: BTTypes0.hpp:992
bool addService(const std::shared_ptr< const jau::uuid_t > &uuid) noexcept
Definition: BTTypes0.cpp:834
void setConnInterval(const uint16_t min, const uint16_t max) noexcept
Set slave connection interval range.
Definition: BTTypes0.hpp:1014
Persistent endian aware octet data, i.e.
Definition: octets.hpp:560
std::string toString() const
Definition: octets.hpp:932
Transient read only and endian aware octet data, i.e.
Definition: octets.hpp:67
std::string toString() const noexcept
Definition: octets.hpp:288
constexpr nsize_t size() const noexcept
Returns the used memory size for read and write operations, may be zero.
Definition: octets.hpp:162
constexpr uint8_t const * get_ptr() const noexcept
Definition: octets.hpp:272
This class provides a RAII-style Sequentially Consistent (SC) data race free (DRF) critical block.
Service runner, a reusable dedicated thread performing custom user services.
bool stop() noexcept
Stops this service, if running.
void start() noexcept
Starts this service, if not running already.
static const uint8_t filter_policy
static const jau::uuid128_t StaticDataUUID
static bool RUN_ONLY_ONCE
int main(int argc, char *argv[])
static std::string adapter_name
static BTSecurityLevel adapter_sec_level
static uint64_t timestamp_t0
static bool SHOW_UPDATE_EVENTS
static const uint16_t adv_interval_max
static const jau::uuid128_t DataServiceUUID
static jau::sc_atomic_bool sync_data
static bool use_SC
static const uint8_t adv_chan_map
DBGattServerRef dbGattServer(new DBGattServer(jau::make_darray(std::make_shared< DBGattService >(true, std::make_unique< const jau::uuid16_t >(GattServiceType::GENERIC_ACCESS), jau::make_darray(std::make_shared< DBGattChar >(std::make_unique< const jau::uuid16_t >(GattCharacteristicType::DEVICE_NAME), BTGattChar::PropertyBitVal::Read, jau::darray< DBGattDescRef >(), make_gvalue(adapter_name.c_str(), 128), true), std::make_shared< DBGattChar >(std::make_unique< const jau::uuid16_t >(GattCharacteristicType::APPEARANCE), BTGattChar::PropertyBitVal::Read, jau::darray< DBGattDescRef >(), make_gvalue((uint16_t) 0)))), std::make_shared< DBGattService >(true, std::make_unique< const jau::uuid16_t >(GattServiceType::DEVICE_INFORMATION), jau::make_darray(std::make_shared< DBGattChar >(std::make_unique< const jau::uuid16_t >(GattCharacteristicType::MANUFACTURER_NAME_STRING), BTGattChar::PropertyBitVal::Read, jau::darray< DBGattDescRef >(), make_gvalue("Gothel Software")), std::make_shared< DBGattChar >(std::make_unique< const jau::uuid16_t >(GattCharacteristicType::MODEL_NUMBER_STRING), BTGattChar::PropertyBitVal::Read, jau::darray< DBGattDescRef >(), make_gvalue("2.4.0-pre")), std::make_shared< DBGattChar >(std::make_unique< const jau::uuid16_t >(GattCharacteristicType::SERIAL_NUMBER_STRING), BTGattChar::PropertyBitVal::Read, jau::darray< DBGattDescRef >(), make_gvalue("sn:0123456789")), std::make_shared< DBGattChar >(std::make_unique< const jau::uuid16_t >(GattCharacteristicType::HARDWARE_REVISION_STRING), BTGattChar::PropertyBitVal::Read, jau::darray< DBGattDescRef >(), make_gvalue("hw:0123456789")), std::make_shared< DBGattChar >(std::make_unique< const jau::uuid16_t >(GattCharacteristicType::FIRMWARE_REVISION_STRING), BTGattChar::PropertyBitVal::Read, jau::darray< DBGattDescRef >(), make_gvalue("fw:0123456789")), std::make_shared< DBGattChar >(std::make_unique< const jau::uuid16_t >(GattCharacteristicType::SOFTWARE_REVISION_STRING), BTGattChar::PropertyBitVal::Read, jau::darray< DBGattDescRef >(), make_gvalue("sw:0123456789")))), std::make_shared< DBGattService >(true, std::make_unique< const jau::uuid128_t >(DataServiceUUID), jau::make_darray(std::make_shared< DBGattChar >(std::make_unique< const jau::uuid128_t >(StaticDataUUID), BTGattChar::PropertyBitVal::Read, jau::make_darray(std::make_shared< DBGattDesc >(BTGattDesc::TYPE_USER_DESC, make_gvalue("DATA_STATIC"))), make_gvalue("Proprietary Static Data 0x00010203")), std::make_shared< DBGattChar >(std::make_unique< const jau::uuid128_t >(CommandUUID), BTGattChar::PropertyBitVal::WriteNoAck|BTGattChar::PropertyBitVal::WriteWithAck, jau::make_darray(std::make_shared< DBGattDesc >(BTGattDesc::TYPE_USER_DESC, make_gvalue("COMMAND"))), make_gvalue(128, 64), true), std::make_shared< DBGattChar >(std::make_unique< const jau::uuid128_t >(ResponseUUID), BTGattChar::PropertyBitVal::Notify|BTGattChar::PropertyBitVal::Indicate, jau::make_darray(std::make_shared< DBGattDesc >(BTGattDesc::TYPE_USER_DESC, make_gvalue("RESPONSE")), DBGattDesc::createClientCharConfig()), make_gvalue((uint16_t) 0)), std::make_shared< DBGattChar >(std::make_unique< const jau::uuid128_t >(PulseDataUUID), BTGattChar::PropertyBitVal::Notify|BTGattChar::PropertyBitVal::Indicate, jau::make_darray(std::make_shared< DBGattDesc >(BTGattDesc::TYPE_USER_DESC, make_gvalue("DATA_PULSE")), DBGattDesc::createClientCharConfig()), make_gvalue("Synthethic Sensor 01")))))))
static void processDisconnectedDevice(BTDeviceRef device)
static std::shared_ptr< BTAdapter > chosenAdapter
static void myChangedAdapterSetFunc(const bool added, std::shared_ptr< BTAdapter > &adapter)
static bool initAdapter(std::shared_ptr< BTAdapter > &adapter)
static const jau::uuid128_t PulseDataUUID
static jau::relaxed_atomic_nsize_t servedConnections
static BTDeviceRef getDevice()
static bool stopAdvertising(BTAdapter *a, std::string msg)
static std::string adapter_short_name
static const jau::uuid128_t ResponseUUID
static BTMode btMode
static const jau::uuid128_t CommandUUID
static bool startAdvertising(BTAdapter *a, std::string msg)
static void setDevice(const BTDeviceRef &cd)
static BTDeviceRef connectedDevice
static const uint16_t adv_interval_min
static EUI48 useAdapter
static const AD_PDU_Type adv_type
static SMPIOCapability adapter_sec_io_cap
void test()
static bool matches(const BTDeviceRef &device)
constexpr const char SERVER_KEY_PATH[]
uint32_t dfa_utf8_decode(uint32_t &state, uint32_t &codep, const uint32_t byte_value)
std::string to_string(const alphabet &v) noexcept
Definition: base_codec.hpp:97
constexpr const jau::fraction_i64 THREAD_SHUTDOWN_TIMEOUT_MS
Maximum time in fractions of seconds to wait for a thread shutdown.
Definition: DBTConst.hpp:73
SMPPairingState
SMP Pairing Process state definition.
Definition: SMPTypes.hpp:107
constexpr SMPIOCapability to_SMPIOCapability(const uint8_t v) noexcept
Definition: SMPTypes.hpp:223
SMPIOCapability
Vol 3, Part H, 2.3.2 IO capabilities.
Definition: SMPTypes.hpp:209
Entry * getStartOf(const EUI48 &addr, const std::string &name) noexcept
Returns a matching Entry,.
constexpr BTSecurityLevel to_BTSecurityLevel(const uint8_t v) noexcept
Definition: BTTypes0.hpp:300
BTMode
Bluetooth adapter operating mode.
Definition: BTTypes0.hpp:112
LE_Features
HCI Supported Commands.
Definition: BTTypes0.hpp:162
DiscoveryPolicy
Discovery policy defines the BTAdapter discovery mode after connecting a remote BTDevice:
Definition: BTAdapter.hpp:82
std::shared_ptr< BTDevice > BTDeviceRef
Definition: BTDevice.hpp:1347
std::string to_string(const DiscoveryPolicy v) noexcept
Definition: BTAdapter.cpp:58
LE_PHYs
LE Transport PHY bit values.
Definition: BTTypes0.hpp:231
Entry * get(const EUI48 &addr, const std::string &name, AddressNameEntryMatchFunc m) noexcept
Returns a matching BTSecurityRegistry::Entry with the given addr and/or name.
ScanType
Meta ScanType as derived from BTMode, with defined value mask consisting of BDAddressType bits.
Definition: BTTypes0.hpp:350
AdapterSetting
Adapter Setting Bits.
Definition: BTTypes1.hpp:144
constexpr bool isAdapterSettingBitSet(const AdapterSetting mask, const AdapterSetting bit) noexcept
Definition: BTTypes1.hpp:185
BTMode to_BTMode(const std::string &value) noexcept
Maps the specified name to a constant of BTMode.
Definition: BTTypes0.cpp:226
BTSecurityLevel
Bluetooth Security Level.
Definition: BTTypes0.hpp:267
AD_PDU_Type
LE Advertising (AD) Protocol Data Unit (PDU) Types.
Definition: BTTypes0.hpp:397
PairingMode
Bluetooth secure pairing mode.
Definition: BTTypes0.hpp:317
HCIStatusCode
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
Definition: HCITypes.hpp:138
EIRDataType
Bit mask of 'Extended Inquiry Response' (EIR) data fields, indicating a set of related data.
Definition: BTTypes0.hpp:838
std::shared_ptr< DBGattDesc > DBGattDescRef
jau::POctets make_gvalue(const char *name)
Convenience jau::POctets ctor function to create DBGattChar or DBGattDesc values.
std::shared_ptr< DBGattService > DBGattServiceRef
std::shared_ptr< DBGattServer > DBGattServerRef
std::shared_ptr< DBGattChar > DBGattCharRef
constexpr darray< First > make_darray(First &&arg1, Next &&... argsN)
Construct a darray<T> instance, initialized by move semantics from the variadic (template pack) argum...
Definition: darray.hpp:1373
void sync() noexcept
Synchronizes filesystems, i.e.
Definition: file_util.cpp:1932
jau::function< R(A...)> bind_member(C1 *base, R(C0::*mfunc)(A...)) noexcept
Bind given class instance and non-void member function to an anonymous function using func_member_tar...
constexpr uint32_t number(const iostate rhs) noexcept
Definition: byte_stream.hpp:72
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
std::string to_decstring(const value_type &v, const char separator=',', const nsize_t width=0) noexcept
Produce a decimal string representation of an integral integer value.
constexpr bool is_set(const cpu_family_t mask, const cpu_family_t bit) noexcept
Definition: cpuid.hpp:122
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
int fprintf_td(const uint64_t elapsed_ms, FILE *stream, const char *format,...) noexcept
Convenient fprintf() invocation, prepending the given elapsed_ms timestamp.
Definition: debug.cpp:270
uint64_t getCurrentMilliseconds() noexcept
Returns current monotonic time in milliseconds.
Definition: basic_types.cpp:64
bool sleep_for(const fraction_timespec &relative_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_for causes the current thread to block until a specific amount of time has passed.
constexpr int getPairingPasskey() const noexcept
constexpr bool getPairingNumericComparison() const noexcept
A packed 48 bit EUI-48 identifier, formerly known as MAC-48 or simply network device MAC address (Med...
Definition: eui48.hpp:324
CXX_ALWAYS_INLINE _Tp load() const noexcept
@ GENERIC_ACCESS
This service contains generic information about the device.
@ DEVICE_INFORMATION
This service exposes manufacturer and/or vendor information about a device.
@ Notify
@ Indicate
@ WriteNoAck
@ Read
@ WriteWithAck
@ SOFTWARE_REVISION_STRING
@ SERIAL_NUMBER_STRING
@ MODEL_NUMBER_STRING
@ DEVICE_NAME
@ APPEARANCE
@ MANUFACTURER_NAME_STRING
@ FIRMWARE_REVISION_STRING
@ HARDWARE_REVISION_STRING