summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/direct_bt/DBTAdapter.hpp12
-rw-r--r--api/direct_bt/DBTDevice.hpp27
-rw-r--r--examples/direct_bt_scanner00/dbt_scanner00.cpp26
-rw-r--r--examples/direct_bt_scanner01/dbt_scanner01.cpp20
-rw-r--r--examples/direct_bt_scanner10/dbt_scanner10.cpp363
-rw-r--r--java/direct_bt/tinyb/DBTAdapter.java9
-rw-r--r--java/jni/direct_bt/DBTAdapter.cxx20
-rw-r--r--src/direct_bt/DBTAdapter.cpp20
-rw-r--r--src/direct_bt/DBTDevice.cpp47
-rw-r--r--src/direct_bt/HCIComm.cpp5
10 files changed, 472 insertions, 77 deletions
diff --git a/api/direct_bt/DBTAdapter.hpp b/api/direct_bt/DBTAdapter.hpp
index ec66a74a..06c21de2 100644
--- a/api/direct_bt/DBTAdapter.hpp
+++ b/api/direct_bt/DBTAdapter.hpp
@@ -118,11 +118,11 @@ namespace direct_bt {
std::shared_ptr<HCIComm> hciComm;
std::vector<std::shared_ptr<DBTDevice>> connectedDevices;
- std::recursive_mutex mtx_connectedDevices;
-
std::vector<std::shared_ptr<DBTDevice>> discoveredDevices; // all discovered devices
std::vector<std::shared_ptr<DBTDevice>> sharedDevices; // all active shared devices
std::vector<std::shared_ptr<AdapterStatusListener>> statusListenerList;
+ std::recursive_mutex mtx_hci;
+ std::recursive_mutex mtx_connectedDevices;
std::recursive_mutex mtx_discoveredDevices;
std::recursive_mutex mtx_sharedDevices;
std::recursive_mutex mtx_statusListenerList;
@@ -249,15 +249,15 @@ namespace direct_bt {
DBTManager& getManager() const { return mgmt; }
/**
- * Returns a reference to the newly opened HCIComm instance
- * if successful, otherwise nullptr is returned.
+ * Returns a reference to the already opened HCIComm
+ * or the newly opened HCIComm instance, otherwise nullptr if no success.
*/
std::shared_ptr<HCIComm> openHCI();
/**
- * Returns the {@link #openHCI()} session or {@code nullptr} if closed.
+ * Returns the {@link #openHCI()} HCIComm or {@code nullptr} if closed.
*/
- std::shared_ptr<HCIComm> getOpenHCIComm() const { return hciComm; }
+ std::shared_ptr<HCIComm> getHCI() const;
/**
* Closes the HCIComm instance
diff --git a/api/direct_bt/DBTDevice.hpp b/api/direct_bt/DBTDevice.hpp
index 9edf1c6d..6271b982 100644
--- a/api/direct_bt/DBTDevice.hpp
+++ b/api/direct_bt/DBTDevice.hpp
@@ -65,6 +65,7 @@ namespace direct_bt {
std::shared_ptr<ManufactureSpecificData> msd = nullptr;
std::vector<std::shared_ptr<uuid_t>> services;
std::shared_ptr<GATTHandler> gattHandler = nullptr;
+ std::recursive_mutex mtx_data;
std::recursive_mutex mtx_gatt;
DBTDevice(DBTAdapter & adapter, EInfoReport const & r);
@@ -78,6 +79,7 @@ namespace direct_bt {
std::shared_ptr<DBTDevice> getSharedInstance() const;
void releaseSharedInstance() const;
+ void notifyDisconnected();
public:
const uint64_t ts_creation;
@@ -110,14 +112,12 @@ namespace direct_bt {
bool isLEAddressType() const { return BDADDR_LE_PUBLIC == addressType || BDADDR_LE_RANDOM == addressType; }
bool isBREDRAddressType() const { return BDADDR_BREDR == addressType; }
- std::string const & getName() const { return name; }
- bool hasName() const { return name.length()>0; }
int8_t getRSSI() const { return rssi; }
int8_t getTxPower() const { return tx_power; }
uint16_t getAppearance() const { return appearance; }
- std::shared_ptr<ManufactureSpecificData> const getManufactureSpecificData() const { return msd; }
-
- std::vector<std::shared_ptr<uuid_t>> getServices() const { return services; }
+ std::string const getName() const;
+ std::shared_ptr<ManufactureSpecificData> const getManufactureSpecificData() const;
+ std::vector<std::shared_ptr<uuid_t>> getServices() const;
/** Returns index >= 0 if found, otherwise -1 */
int findService(std::shared_ptr<uuid_t> const &uuid) const;
@@ -143,7 +143,7 @@ namespace direct_bt {
* Returns the new connection handle or 0 if not successful.
* </p>
* <p>
- * The device is tracked by the managing adapter's HCISession instance.
+ * The device is tracked by the managing adapter.
* </p>
* <p>
* Default parameter values are chosen for using public address resolution
@@ -167,7 +167,7 @@ namespace direct_bt {
* Returns the new connection handle or 0 if not successful.
* </p>
* <p>
- * The device is tracked by the managing adapter's HCISession instance.
+ * The device is tracked by the managing adapter.
* </p>
*/
uint16_t connectHCI(const uint16_t pkt_type=HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5,
@@ -183,7 +183,7 @@ namespace direct_bt {
* Returns the new connection handle or 0 if not successful.
* </p>
* <p>
- * The device is tracked by the managing adapter's HCISession instance.
+ * The device is tracked by the managing adapter.
* </p>
*/
uint16_t connectHCIDefault();
@@ -195,7 +195,7 @@ namespace direct_bt {
/**
* Disconnect the LE or BREDR peer's GATT and HCI connection.
* <p>
- * The device will be removed from the managing adapter's HCISession instance.
+ * The device will be removed from the managing adapter's connected devices.
* </p>
* <p>
* An open GATTHandler will also be closed via disconnectGATT()
@@ -220,8 +220,8 @@ namespace direct_bt {
/**
* Returns a newly established GATT connection or an already open GATT connection.
* <p>
- * The HCI le_connect or HCI connect (defaultConnect) must be performed first,
- * to produce orderly behavior and best performance.
+ * The HCI le_connect or HCI connect shall be performed first,
+ * to produce best performance. See {@link #connectHCIDefault()}.
* </p>
* <p>
* The returned GATTHandler is managed by this device instance
@@ -238,13 +238,10 @@ namespace direct_bt {
* Returns a list of shared GATTServices available on this device if successful,
* otherwise returns an empty list.
* <p>
- * In case no HCI connection has been established yet, connectHCIDefault() will be performed.
- * </p>
- * <p>
* In case no GATT connection has been established yet, connectGATT(..) will be performed.
* </p>
*/
- std::vector<std::shared_ptr<GATTService>> getServices();
+ std::vector<std::shared_ptr<GATTService>> getGATTServices();
/**
* Explicit disconnecting an open GATTHandler, which is usually performed via disconnect()
diff --git a/examples/direct_bt_scanner00/dbt_scanner00.cpp b/examples/direct_bt_scanner00/dbt_scanner00.cpp
index ba7ba732..966f16d5 100644
--- a/examples/direct_bt_scanner00/dbt_scanner00.cpp
+++ b/examples/direct_bt_scanner00/dbt_scanner00.cpp
@@ -185,10 +185,12 @@ int main(int argc, char *argv[])
const int64_t t0 = getCurrentMilliseconds();
- std::shared_ptr<HCIComm> hci = adapter.openHCI();
- if( nullptr == hci || !hci->isOpen() ) {
- fprintf(stderr, "Couldn't open HCI from %s\n", adapter.toString().c_str());
- exit(1);
+ if( doHCI_Connect ) {
+ std::shared_ptr<HCIComm> hci = adapter.openHCI();
+ if( nullptr == hci || !hci->isOpen() ) {
+ fprintf(stderr, "Couldn't open HCI from %s\n", adapter.toString().c_str());
+ exit(1);
+ }
}
while( ok && ( forever || !foundDevice ) ) {
@@ -218,9 +220,23 @@ int main(int argc, char *argv[])
const uint64_t t1 = getCurrentMilliseconds();
//
+ // HCI LE-Connect
+ // (Without: Overall communication takes ~twice as long!!!)
+ //
+ if( doHCI_Connect ) {
+ if( 0 == device->connectHCIDefault() ) {
+ fprintf(stderr, "Connect: Failed %s\n", device->toString().c_str());
+ } else {
+ fprintf(stderr, "Connect: Success\n");
+ }
+ } else {
+ fprintf(stderr, "Connect: Skipped %s\n", device->toString().c_str());
+ }
+
+ //
// GATT Service Processing
//
- std::vector<GATTServiceRef> primServices = device->getServices(); // implicit HCI and GATT connect...
+ std::vector<GATTServiceRef> primServices = device->getGATTServices(); // implicit GATT connect...
if( primServices.size() > 0 ) {
const uint64_t t5 = getCurrentMilliseconds();
{
diff --git a/examples/direct_bt_scanner01/dbt_scanner01.cpp b/examples/direct_bt_scanner01/dbt_scanner01.cpp
index 9844ee30..7eb50d62 100644
--- a/examples/direct_bt_scanner01/dbt_scanner01.cpp
+++ b/examples/direct_bt_scanner01/dbt_scanner01.cpp
@@ -183,10 +183,12 @@ int main(int argc, char *argv[])
const int64_t t0 = getCurrentMilliseconds();
- std::shared_ptr<HCIComm> hci = adapter.openHCI();
- if( nullptr == hci || !hci->isOpen() ) {
- fprintf(stderr, "Couldn't open HCI from %s\n", adapter.toString().c_str());
- exit(1);
+ if( doHCI_Connect ) {
+ std::shared_ptr<HCIComm> hci = adapter.openHCI();
+ if( nullptr == hci || !hci->isOpen() ) {
+ fprintf(stderr, "Couldn't open HCI from %s\n", adapter.toString().c_str());
+ exit(1);
+ }
}
while( ok && ( forever || !foundDevice ) ) {
@@ -219,17 +221,14 @@ int main(int argc, char *argv[])
// HCI LE-Connect
// (Without: Overall communication takes ~twice as long!!!)
//
- uint16_t hciConnHandle;
if( doHCI_Connect ) {
- hciConnHandle = device->connectHCIDefault();
- if( 0 == hciConnHandle ) {
+ if( 0 == device->connectHCIDefault() ) {
fprintf(stderr, "Connect: Failed %s\n", device->toString().c_str());
} else {
fprintf(stderr, "Connect: Success\n");
}
} else {
fprintf(stderr, "Connect: Skipped %s\n", device->toString().c_str());
- hciConnHandle = 0;
}
const uint64_t t3 = getCurrentMilliseconds();
const uint64_t td03 = t3 - t0;
@@ -238,9 +237,8 @@ int main(int argc, char *argv[])
fprintf(stderr, " discovery-only %" PRIu64 " ms,\n"
" connect-only %" PRIu64 " ms,\n"
" discovered to hci-connected %" PRIu64 " ms,\n"
- " total %" PRIu64 " ms,\n"
- " handle 0x%X\n",
- td01, td13, (t3 - device->getCreationTimestamp()), td03, hciConnHandle);
+ " total %" PRIu64 " ms,\n",
+ td01, td13, (t3 - device->getCreationTimestamp()), td03);
//
// GATT Processing
diff --git a/examples/direct_bt_scanner10/dbt_scanner10.cpp b/examples/direct_bt_scanner10/dbt_scanner10.cpp
new file mode 100644
index 00000000..b5a7ebb8
--- /dev/null
+++ b/examples/direct_bt_scanner10/dbt_scanner10.cpp
@@ -0,0 +1,363 @@
+/*
+ * Author: Sven Gothel <[email protected]>
+ * 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 <direct_bt/DirectBT.hpp>
+#include <cinttypes>
+
+extern "C" {
+ #include <unistd.h>
+}
+
+using namespace direct_bt;
+
+/***
+ * This C++ direct_bt scanner code uses the high-level API like dbt_scanner00
+ * and adds multithreading, i.e. one thread processes each found device found
+ * as notified via the event listener.
+ */
+
+static int64_t timestamp_t0;
+
+static EUI48 waitForDevice = EUI48_ANY_DEVICE;
+
+static void deviceConnectTask(std::shared_ptr<DBTDevice> device);
+
+static void deviceProcessTask(std::shared_ptr<DBTDevice> device);
+
+#include <pthread.h>
+
+class DeviceTask {
+ public:
+ std::shared_ptr<DBTDevice> device;
+ std::thread worker;
+
+ DeviceTask(std::shared_ptr<DBTDevice> d)
+ : device(d),
+ worker( std::thread(::deviceProcessTask, d) )
+ {
+ worker.detach();
+ fprintf(stderr, "DeviceTask ctor: %s\n", d->toString().c_str());
+ }
+
+ DeviceTask(const DeviceTask &o) noexcept = default;
+ DeviceTask(DeviceTask &&o) noexcept = default;
+ DeviceTask& operator=(const DeviceTask &o) noexcept = default;
+ DeviceTask& operator=(DeviceTask &&o) noexcept = default;
+
+ ~DeviceTask() {
+ fprintf(stderr, "DeviceTask dtor: %s\n", device->toString().c_str());
+ }
+
+};
+
+/**
+ * TODO: Analyze why 'vector<DeviceTask>' regarding field 'std::thread'
+ * does _not_ work. Instance vector of DeviceTask with std::thread
+ * causes multiple occasions of SIGSEGFAULT and mutex issues!
+ */
+static std::vector<std::shared_ptr<DeviceTask>> deviceTasks;
+static std::recursive_mutex mtx_deviceTasks;
+
+static int getDeviceTaskCount() {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_deviceTasks); // RAII-style acquire and relinquish via destructor
+ return deviceTasks.size();
+}
+static bool isDeviceTaskInProgress(std::shared_ptr<DBTDevice> d) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_deviceTasks); // RAII-style acquire and relinquish via destructor
+ for (auto it = deviceTasks.begin(); it != deviceTasks.end(); ++it) {
+ if ( *d == *(*it)->device ) {
+ return true;
+ }
+ }
+ return false;
+}
+static bool addDeviceTask(std::shared_ptr<DBTDevice> d) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_deviceTasks); // RAII-style acquire and relinquish via destructor
+ if( !isDeviceTaskInProgress(d) ) {
+ deviceTasks.push_back( std::shared_ptr<DeviceTask>( new DeviceTask(d) ) );
+ return true;
+ }
+ return false;
+}
+static bool removeDeviceTask(std::shared_ptr<DBTDevice> d) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_deviceTasks); // RAII-style acquire and relinquish via destructor
+ for (auto it = deviceTasks.begin(); it != deviceTasks.end(); ) {
+ if ( *d == *(*it)->device ) {
+ it = deviceTasks.erase(it);
+ return true;
+ } else {
+ ++it;
+ }
+ }
+ return false;
+}
+
+static std::recursive_mutex mtx_devicesProcessed;
+static std::vector<EUI48> devicesProcessed;
+
+static void addDevicesProcessed(const EUI48 &a) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
+ devicesProcessed.push_back(a);
+}
+static bool isDeviceProcessed(const EUI48 & a) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_devicesProcessed); // RAII-style acquire and relinquish via destructor
+ for (auto it = devicesProcessed.begin(); it != devicesProcessed.end(); ++it) {
+ if ( a == *it ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+class MyAdapterStatusListener : public AdapterStatusListener {
+
+ void adapterSettingsChanged(DBTAdapter const &a, const AdapterSetting oldmask, const AdapterSetting newmask,
+ const AdapterSetting changedmask, const uint64_t timestamp) override {
+ fprintf(stderr, "****** SETTINGS_CHANGED: %s -> %s, changed %s\n",
+ adapterSettingsToString(oldmask).c_str(),
+ adapterSettingsToString(newmask).c_str(),
+ adapterSettingsToString(changedmask).c_str());
+ fprintf(stderr, "Status DBTAdapter:\n");
+ fprintf(stderr, "%s\n", a.toString().c_str());
+ (void)timestamp;
+ }
+
+ void deviceFound(std::shared_ptr<DBTDevice> device, const uint64_t timestamp) override {
+ (void)timestamp;
+
+ if( waitForDevice == EUI48_ANY_DEVICE ||
+ ( waitForDevice == device->address && !isDeviceProcessed(waitForDevice) ) )
+ {
+ fprintf(stderr, "****** FOUND__-0: Connecting %s\n", device->toString().c_str());
+ std::thread dc(::deviceConnectTask, device);
+ dc.detach();
+ } else {
+ fprintf(stderr, "****** FOUND__-1: NOP %s\n", device->toString().c_str());
+ }
+ }
+ void deviceUpdated(std::shared_ptr<DBTDevice> device, const uint64_t timestamp, const EIRDataType updateMask) override {
+ fprintf(stderr, "****** UPDATED: %s of %s\n", eirDataMaskToString(updateMask).c_str(), device->toString().c_str());
+ (void)timestamp;
+ }
+ void deviceConnected(std::shared_ptr<DBTDevice> device, const uint64_t timestamp) override {
+ (void)timestamp;
+
+ if( waitForDevice == EUI48_ANY_DEVICE ||
+ ( waitForDevice == device->address && !isDeviceProcessed(waitForDevice) ) )
+ {
+ fprintf(stderr, "****** CONNECTED-0: Processing %s\n", device->toString().c_str());
+ addDeviceTask( device );
+ } else {
+ fprintf(stderr, "****** CONNECTED-1: NOP %s\n", device->toString().c_str());
+ }
+ }
+ void deviceDisconnected(std::shared_ptr<DBTDevice> device, const uint64_t timestamp) override {
+ fprintf(stderr, "****** DISCONNECTED: %s\n", device->toString().c_str());
+ (void)timestamp;
+ }
+};
+
+static const uuid16_t _TEMPERATURE_MEASUREMENT(GattCharacteristicType::TEMPERATURE_MEASUREMENT);
+
+class MyGATTEventListener : public SpecificGATTCharacteristicListener {
+ public:
+
+ MyGATTEventListener(const GATTCharacteristic * characteristicMatch)
+ : SpecificGATTCharacteristicListener(characteristicMatch) {}
+
+ void notificationReceived(GATTCharacteristicRef charDecl, std::shared_ptr<TROOctets> charValue, const uint64_t timestamp) override {
+ const std::shared_ptr<DBTDevice> dev = charDecl->getDevice();
+ const int64_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(GATTCharacteristicRef charDecl,
+ std::shared_ptr<TROOctets> charValue, const uint64_t timestamp,
+ const bool confirmationSent) override
+ {
+ const std::shared_ptr<DBTDevice> dev = charDecl->getDevice();
+ const int64_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<TemperatureMeasurementCharateristic> temp = TemperatureMeasurementCharateristic::get(*charValue);
+ if( nullptr != temp ) {
+ fprintf(stderr, "****** valu %s\n", temp->toString().c_str());
+ }
+ }
+ }
+ fprintf(stderr, "****** rawv %s\n", charValue->toString().c_str());
+ }
+};
+
+static void deviceConnectTask(std::shared_ptr<DBTDevice> device) {
+ fprintf(stderr, "****** Device Connector: Start %s\n", device->toString().c_str());
+ device->getAdapter().stopDiscovery();
+ bool res = device->connectHCIDefault();
+ fprintf(stderr, "****** Device Connector: End result %d of %s\n", res, device->toString().c_str());
+ if( !res && 0 == getDeviceTaskCount() ) {
+ fprintf(stderr, "****** Device Connector: startDiscovery()\n");
+ device->getAdapter().startDiscovery();
+ }
+}
+
+static void deviceProcessTask(std::shared_ptr<DBTDevice> device) {
+ fprintf(stderr, "****** Device Process: Start %s\n", device->toString().c_str());
+ const uint64_t t1 = getCurrentMilliseconds();
+
+ //
+ // GATT Service Processing
+ //
+ std::vector<GATTServiceRef> primServices;
+ std::shared_ptr<GATTHandler> gatt = device->connectGATT();
+ if( nullptr == gatt ) {
+ fprintf(stderr, "****** Device Process: GATT Connect failed\n");
+ goto out;
+ }
+ primServices = device->getGATTServices(); // implicit GATT connect...
+ if( primServices.size() > 0 ) {
+ const uint64_t t5 = getCurrentMilliseconds();
+ {
+ const uint64_t td15 = t5 - t1; // connected -> gatt-complete
+ const uint64_t tdc5 = t5 - device->getCreationTimestamp(); // discovered to gatt-complete
+ const uint64_t td05 = t5 - timestamp_t0; // adapter-init -> gatt-complete
+ fprintf(stderr, "\n\n\n");
+ fprintf(stderr, "GATT primary-services completed\n");
+ fprintf(stderr, " connected to gatt-complete %" PRIu64 " ms,\n"
+ " discovered to gatt-complete %" PRIu64 " ms (connect %" PRIu64 " ms),\n"
+ " adapter-init to gatt-complete %" PRIu64 " ms\n\n",
+ td15, tdc5, (tdc5 - td15), td05);
+ }
+
+ for(size_t i=0; i<primServices.size(); i++) {
+ GATTService & 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);
+ std::vector<GATTCharacteristicRef> & serviceCharacteristics = primService.characteristicList;
+ for(size_t j=0; j<serviceCharacteristics.size(); j++) {
+ GATTCharacteristic & serviceChar = *serviceCharacteristics.at(j);
+ fprintf(stderr, " [%2.2d.%2.2d] Decla: %s\n", (int)i, (int)j, serviceChar.toString().c_str());
+ if( serviceChar.hasProperties(GATTCharacteristic::PropertyBitVal::Read) ) {
+ POctets value(GATTHandler::ClientMaxMTU, 0);
+ if( serviceChar.readValue(value) ) {
+ fprintf(stderr, " [%2.2d.%2.2d] Value: %s\n", (int)i, (int)j, value.toString().c_str());
+ }
+ }
+ bool cccdEnableResult[2];
+ bool cccdRet = serviceChar.configIndicationNotification(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.addCharacteristicListener( std::shared_ptr<GATTCharacteristicListener>( new MyGATTEventListener(&serviceChar) ) );
+ }
+ }
+ }
+ // FIXME sleep 1s for potential callbacks ..
+ sleep(1);
+ }
+ device->disconnect();
+
+out:
+ addDevicesProcessed(device->getAddress());
+ if( 1 >= getDeviceTaskCount() ) {
+ fprintf(stderr, "****** Device Process: startDiscovery()\n");
+ device->getAdapter().startDiscovery();
+ }
+ removeDeviceTask(device);
+ fprintf(stderr, "****** Device Process: End\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+ int dev_id = 0; // default
+ bool waitForEnter=false;
+ bool done = false;
+
+ for(int i=1; i<argc; i++) {
+ if( !strcmp("-wait", argv[i]) ) {
+ waitForEnter = true;
+ } else if( !strcmp("-dev_id", argv[i]) && argc > (i+1) ) {
+ dev_id = atoi(argv[++i]);
+ } else if( !strcmp("-mac", argv[i]) && argc > (i+1) ) {
+ std::string macstr = std::string(argv[++i]);
+ waitForDevice = EUI48(macstr);
+ }
+ }
+ fprintf(stderr, "dev_id %d\n", dev_id);
+ fprintf(stderr, "waitForDevice: %s\n", waitForDevice.toString().c_str());
+
+ if( waitForEnter ) {
+ fprintf(stderr, "Press ENTER to continue\n");
+ getchar();
+ }
+
+ timestamp_t0 = getCurrentMilliseconds();
+
+ DBTAdapter adapter(dev_id);
+ if( !adapter.hasDevId() ) {
+ fprintf(stderr, "Default adapter not available.\n");
+ exit(1);
+ }
+ if( !adapter.isValid() ) {
+ fprintf(stderr, "Adapter invalid.\n");
+ exit(1);
+ }
+ fprintf(stderr, "Using adapter: device %s, address %s: %s\n",
+ adapter.getName().c_str(), adapter.getAddressString().c_str(), adapter.toString().c_str());
+
+ adapter.addStatusListener(std::shared_ptr<AdapterStatusListener>(new MyAdapterStatusListener()));
+
+ std::shared_ptr<HCIComm> hci = adapter.openHCI();
+ if( nullptr == hci || !hci->isOpen() ) {
+ fprintf(stderr, "Couldn't open HCI from %s\n", adapter.toString().c_str());
+ exit(1);
+ }
+
+ if( !adapter.startDiscovery() ) {
+ perror("Adapter start discovery failed");
+ goto out;
+ }
+
+ do {
+ if( waitForDevice != EUI48_ANY_DEVICE && isDeviceProcessed(waitForDevice) ) {
+ fprintf(stderr, "****** WaitForDevice processed %s", waitForDevice.toString().c_str());
+ done = true;
+ }
+ sleep(3);
+ } while( !done );
+
+out:
+ adapter.closeHCI();
+ return 0;
+}
+
diff --git a/java/direct_bt/tinyb/DBTAdapter.java b/java/direct_bt/tinyb/DBTAdapter.java
index 6c9e9f03..9b60d27b 100644
--- a/java/direct_bt/tinyb/DBTAdapter.java
+++ b/java/direct_bt/tinyb/DBTAdapter.java
@@ -233,13 +233,6 @@ public class DBTAdapter extends DBTObject implements BluetoothAdapter
/* internal */
- private synchronized void open() {
- if( !isOpen ) {
- isOpen = openImpl();
- }
- }
- private native boolean openImpl();
-
@Override
protected native void deleteImpl();
@@ -247,7 +240,6 @@ public class DBTAdapter extends DBTObject implements BluetoothAdapter
@Override
public synchronized boolean startDiscovery() throws BluetoothException {
- open();
removeDevices();
final boolean res = startDiscoveryImpl();
isDiscovering = res;
@@ -278,7 +270,6 @@ public class DBTAdapter extends DBTObject implements BluetoothAdapter
@Override
public int removeDevices() throws BluetoothException {
- open();
final int cj = removeDiscoveredDevices();
final int cn = removeDevicesImpl();
if( cj != cn ) {
diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx
index 360084b1..1e32ade8 100644
--- a/java/jni/direct_bt/DBTAdapter.cxx
+++ b/java/jni/direct_bt/DBTAdapter.cxx
@@ -392,21 +392,6 @@ jstring Java_direct_1bt_tinyb_DBTAdapter_toStringImpl(JNIEnv *env, jobject obj)
return nullptr;
}
-jboolean Java_direct_1bt_tinyb_DBTAdapter_openImpl(JNIEnv *env, jobject obj) {
- try {
- DBTAdapter *adapter = getInstance<DBTAdapter>(env, obj);
- DBG_PRINT("Java_direct_1bt_tinyb_DBTAdapter_deleteImpl %s", adapter->toString().c_str());
- std::shared_ptr<direct_bt::HCIComm> hciSession = adapter->openHCI();
- if( nullptr == hciSession ) {
- throw BluetoothException("Couldn't open adapter "+adapter->toString(), E_FILE_LINE);
- }
- return JNI_TRUE;
- } catch(...) {
- rethrow_and_raise_java_exception(env);
- }
- return JNI_FALSE;
-}
-
void Java_direct_1bt_tinyb_DBTAdapter_deleteImpl(JNIEnv *env, jobject obj)
{
try {
@@ -594,6 +579,11 @@ jobject Java_direct_1bt_tinyb_DBTAdapter_connectDevice(JNIEnv *env, jobject obj,
getBDAddressTypeString(addressType).c_str(), getBDAddressTypeString(addressTypeDevice).c_str(),
device->toString().c_str());
}
+
+ std::shared_ptr<direct_bt::HCIComm> hci = adapter->openHCI();
+ if( nullptr == hci ) {
+ throw BluetoothException("Couldn't get or open adapter's HCIComm "+adapter->toString(), E_FILE_LINE);
+ }
std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
JavaGlobalObj::check(jDeviceRef, E_FILE_LINE);
diff --git a/src/direct_bt/DBTAdapter.cpp b/src/direct_bt/DBTAdapter.cpp
index ec6775ee..0ff9a3b6 100644
--- a/src/direct_bt/DBTAdapter.cpp
+++ b/src/direct_bt/DBTAdapter.cpp
@@ -55,7 +55,7 @@ void DBTAdapter::addConnectedDevice(const std::shared_ptr<DBTDevice> & device) {
const std::lock_guard<std::recursive_mutex> lock(mtx_connectedDevices); // RAII-style acquire and relinquish via destructor
for (auto it = connectedDevices.begin(); it != connectedDevices.end(); ++it) {
if ( *device == **it ) {
- ERR_PRINT("DBTAdapter::addConnectedDevice: Device already connected: %s", device->toString().c_str());
+ DBG_PRINT("DBTAdapter::addConnectedDevice: Device already connected: %s", device->toString().c_str());
return;
}
}
@@ -175,9 +175,18 @@ void DBTAdapter::setBondable(bool value) {
std::shared_ptr<HCIComm> DBTAdapter::openHCI()
{
+ const std::lock_guard<std::recursive_mutex> lock(mtx_hci); // RAII-style acquire and relinquish via destructor
+
if( !valid ) {
return nullptr;
}
+ if( nullptr != hciComm ) {
+ if( hciComm->isOpen() ) {
+ DBG_PRINT("DBTAdapter::openHCI: Already open");
+ return hciComm;
+ }
+ hciComm = nullptr;
+ }
HCIComm *s = new HCIComm(dev_id, HCI_CHANNEL_RAW, HCIDefaults::HCI_TO_SEND_REQ_POLL_MS);
if( !s->isOpen() ) {
delete s;
@@ -188,8 +197,15 @@ std::shared_ptr<HCIComm> DBTAdapter::openHCI()
return hciComm;
}
+std::shared_ptr<HCIComm> DBTAdapter::getHCI() const {
+ const std::lock_guard<std::recursive_mutex> lock(const_cast<DBTAdapter*>(this)->mtx_hci); // RAII-style acquire and relinquish via destructor
+ return hciComm;
+}
+
bool DBTAdapter::closeHCI()
{
+ const std::lock_guard<std::recursive_mutex> lock(mtx_hci); // RAII-style acquire and relinquish via destructor
+
DBG_PRINT("DBTAdapter::closeHCI: ...");
if( nullptr == hciComm || !hciComm->isOpen() ) {
DBG_PRINT("DBTAdapter::closeHCI: Not open");
@@ -500,6 +516,8 @@ bool DBTAdapter::mgmtEvDeviceDisconnectedCB(std::shared_ptr<MgmtEvent> e) {
if( nullptr != device ) {
DBG_PRINT("DBTAdapter::EventCB:DeviceDisconnected(dev_id %d): %s\n -> %s",
dev_id, event.toString().c_str(), device->toString().c_str());
+ device->notifyDisconnected();
+ removeConnectedDevice(*device);
for_each_idx_mtx(mtx_statusListenerList, statusListenerList, [&](std::shared_ptr<AdapterStatusListener> &l) {
if( l->matchDevice(*device) ) {
diff --git a/src/direct_bt/DBTDevice.cpp b/src/direct_bt/DBTDevice.cpp
index 75ac8f09..50c9d170 100644
--- a/src/direct_bt/DBTDevice.cpp
+++ b/src/direct_bt/DBTDevice.cpp
@@ -99,10 +99,26 @@ int DBTDevice::findService(std::shared_ptr<uuid_t> const &uuid) const
}
}
+std::string const DBTDevice::getName() const {
+ const std::lock_guard<std::recursive_mutex> lock(const_cast<DBTDevice*>(this)->mtx_data); // RAII-style acquire and relinquish via destructor
+ return name;
+}
+
+std::shared_ptr<ManufactureSpecificData> const DBTDevice::getManufactureSpecificData() const {
+ const std::lock_guard<std::recursive_mutex> lock(const_cast<DBTDevice*>(this)->mtx_data); // RAII-style acquire and relinquish via destructor
+ return msd;
+}
+
+std::vector<std::shared_ptr<uuid_t>> DBTDevice::getServices() const {
+ const std::lock_guard<std::recursive_mutex> lock(const_cast<DBTDevice*>(this)->mtx_data); // RAII-style acquire and relinquish via destructor
+ return services;
+}
+
std::string DBTDevice::toString() const {
+ const std::lock_guard<std::recursive_mutex> lock(const_cast<DBTDevice*>(this)->mtx_data); // RAII-style acquire and relinquish via destructor
const uint64_t t0 = getCurrentMilliseconds();
std::string msdstr = nullptr != msd ? msd->toString() : "MSD[null]";
- std::string out("Device[address["+getAddressString()+", "+getBDAddressTypeString(getAddressType())+"], name['"+getName()+
+ std::string out("Device[address["+getAddressString()+", "+getBDAddressTypeString(getAddressType())+"], name['"+name+
"'], age "+std::to_string(t0-ts_creation)+" ms, lup "+std::to_string(t0-ts_update)+" ms, rssi "+std::to_string(getRSSI())+
", tx-power "+std::to_string(tx_power)+", appearance "+uint16HexString(appearance)+", "+msdstr+", "+javaObjectToString()+"]");
if(services.size() > 0 ) {
@@ -120,6 +136,8 @@ std::string DBTDevice::toString() const {
}
EIRDataType DBTDevice::update(EInfoReport const & data) {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_data); // RAII-style acquire and relinquish via destructor
+
EIRDataType res = EIRDataType::NONE;
ts_update = data.getTimestamp();
if( data.isSet(EIRDataType::BDADDR) ) {
@@ -212,13 +230,15 @@ uint16_t DBTDevice::le_connectHCI(HCIAddressType peer_mac_type, HCIAddressType o
ERR_PRINT("DBTDevice::le_connect: Already connected");
return 0;
}
+
std::shared_ptr<DBTDevice> sharedInstance = getSharedInstance();
if( nullptr == sharedInstance ) {
throw InternalError("DBTDevice::connectGATT: Device unknown to adapter and not tracked: "+toString(), E_FILE_LINE);
}
- std::shared_ptr<HCIComm> hciComm = adapter.getOpenHCIComm();
+ const std::lock_guard<std::recursive_mutex> lock(adapter.mtx_hci); // RAII-style acquire and relinquish via destructor
+ std::shared_ptr<HCIComm> hciComm = adapter.getHCI();
if( nullptr == hciComm || !hciComm->isOpen() ) {
- ERR_PRINT("DBTDevice::le_connect: Adapter session not opened");
+ ERR_PRINT("DBTDevice::le_connect: Adapter's HCIComm not opened");
return 0;
}
if( !isLEAddressType() ) {
@@ -256,9 +276,10 @@ uint16_t DBTDevice::connectHCI(const uint16_t pkt_type, const uint16_t clock_off
if( nullptr == sharedInstance ) {
throw InternalError("DBTDevice::connectGATT: Device unknown to adapter and not tracked: "+toString(), E_FILE_LINE);
}
- std::shared_ptr<HCIComm> hciComm = adapter.getOpenHCIComm();
+ const std::lock_guard<std::recursive_mutex> lock(adapter.mtx_hci); // RAII-style acquire and relinquish via destructor
+ std::shared_ptr<HCIComm> hciComm = adapter.getHCI();
if( nullptr == hciComm || !hciComm->isOpen() ) {
- ERR_PRINT("DBTDevice::le_connect: Adapter session not opened");
+ ERR_PRINT("DBTDevice::le_connect: Adapter's HCIComm not opened");
return 0;
}
if( !isBREDRAddressType() ) {
@@ -298,10 +319,15 @@ uint16_t DBTDevice::connectHCIDefault()
}
}
+void DBTDevice::notifyDisconnected() {
+ hciConnHandle = 0;
+}
+
void DBTDevice::disconnect(const uint8_t reason) {
disconnectGATT();
- std::shared_ptr<HCIComm> hciComm = adapter.getOpenHCIComm();
+ const std::lock_guard<std::recursive_mutex> lock(adapter.mtx_hci); // RAII-style acquire and relinquish via destructor
+ std::shared_ptr<HCIComm> hciComm = adapter.getHCI();
if( 0 == hciConnHandle ) {
DBG_PRINT("DBTDevice::disconnect: Not connected");
@@ -309,7 +335,7 @@ void DBTDevice::disconnect(const uint8_t reason) {
}
if( nullptr == hciComm || !hciComm->isOpen() ) {
- DBG_PRINT("DBTDevice::disconnect: Session not opened");
+ DBG_PRINT("DBTDevice::disconnect: Adapter's HCIComm not opened");
goto errout;
}
@@ -361,13 +387,8 @@ std::shared_ptr<GATTHandler> DBTDevice::getGATTHandler() {
return gattHandler;
}
-std::vector<std::shared_ptr<GATTService>> DBTDevice::getServices() {
+std::vector<std::shared_ptr<GATTService>> DBTDevice::getGATTServices() {
const std::lock_guard<std::recursive_mutex> lock(mtx_gatt); // RAII-style acquire and relinquish via destructor
- std::shared_ptr<DBTDevice> sharedInstance = getSharedInstance();
- if( nullptr == sharedInstance ) {
- ERR_PRINT("DBTDevice::getServices: Device unknown to adapter and not tracked: %s", toString().c_str());
- return std::vector<std::shared_ptr<GATTService>>();
- }
if( nullptr == gattHandler ) {
connectGATT();
if( nullptr == gattHandler ) {
diff --git a/src/direct_bt/HCIComm.cpp b/src/direct_bt/HCIComm.cpp
index 4945e4d8..1a89d853 100644
--- a/src/direct_bt/HCIComm.cpp
+++ b/src/direct_bt/HCIComm.cpp
@@ -32,7 +32,7 @@
#include <algorithm>
-#define VERBOSE_ON 1
+// #define VERBOSE_ON 1
#include <dbt_debug.hpp>
#include "HCIComm.hpp"
@@ -64,7 +64,7 @@ int HCIComm::hci_open_dev(const uint16_t dev_id, const uint16_t channel)
} */
// Create a loose HCI socket
- dd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
+ dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
if (0 > dd ) {
ERR_PRINT("HCIComm::hci_open_dev: socket failed");
return dd;
@@ -341,6 +341,7 @@ bool HCIComm::send_req(const uint16_t opcode, const void *command, const uint8_t
if (exp_event != HCI_EV_CMD_STATUS) {
if (cs->status) {
errno = EIO;
+ ERR_PRINT("hci_send_req: event exp 0x%X != has 0x%X, error status 0x%2.2X", exp_event, hdr->evt, cs->status);
goto failed;
}
break;