aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-04-20 07:21:35 +0200
committerSven Gothel <[email protected]>2020-04-20 07:21:35 +0200
commit6fdcdb13db5e13f11c44f0f9bba088252d9ffa18 (patch)
tree8c9c321dd2064eb53438544f0faba91306629c8c
parent6505f49b63db200d817817d1d01a14005a3d732c (diff)
Initial working Java binding for the direct_bt C++ module
Example ScannerTinyB01 demonstrates efficient scanning devices using the new BluetoothDeviceDiscoveryListener interface. The C++ HCIObject extends JavaUplink, which handles the java object references via 'std::shared_ptr<JavaAnonObj>', where JavaAnonObj relies on later polymorph specialization. JavaAnonObj gets derived in the java/jni of direct_bt, where the JNI header + libraries are available. +++ The java inplementing NativeDownlink implementations store the nativeInstance to the C++ instances as well as handle their java references within the native instances. The C++ JavaUplink and Java NativeDownlink interfaces are complete the cross referencing java <-> native. +++ Native libraries are now split into pairs: - tinyb + javatinyb - direct_bt + javadirect_bt TODO: BluetoothFactory must chose the proper bundle! +++ The Java Adapter received a BluetoothDeviceDiscoveryListener hook, matching C++ Adapter's HCIDeviceDiscoveryListener. Since the Java Adapter implements its own discovery thread, using the BluetoothDeviceDiscoveryListener is more efficient then polling over a list of Devices fetched. ++++ TODO: Align Java and C++ class names, foremost in the C++ direct_bt space. TODO: Bind the whole C++ GATT functionality More testing.
-rw-r--r--.cproject6
-rw-r--r--api/direct_bt/BasicTypes.hpp23
-rw-r--r--api/direct_bt/HCITypes.hpp32
-rw-r--r--api/direct_bt/JavaAccess.hpp63
-rw-r--r--api/direct_bt/MgmtComm.hpp12
-rw-r--r--api/direct_bt/dbt_debug.hpp (renamed from src/direct_bt/dbt_debug.hpp)0
-rw-r--r--examples/direct_bt_scanner/dbt_scanner.cpp5
-rw-r--r--examples/java/CMakeLists.txt13
-rw-r--r--examples/java/ScannerTinyB00.java (renamed from examples/java/ScannerTinyB.java)2
-rw-r--r--examples/java/ScannerTinyB01.java325
-rw-r--r--java/CMakeLists.txt3
-rw-r--r--java/direct_bt/tinyb/Adapter.java417
-rw-r--r--java/direct_bt/tinyb/DBTEvent.java (renamed from java/tinyb/hci/HCIEvent.java)10
-rw-r--r--java/direct_bt/tinyb/DBTObject.java (renamed from java/tinyb/hci/HCIObject.java)31
-rw-r--r--java/direct_bt/tinyb/Device.java (renamed from java/tinyb/hci/HCIDevice.java)64
-rw-r--r--java/direct_bt/tinyb/GattCharacteristic.java (renamed from java/tinyb/hci/HCIGattCharacteristic.java)28
-rw-r--r--java/direct_bt/tinyb/GattDescriptor.java (renamed from java/tinyb/hci/HCIGattDescriptor.java)25
-rw-r--r--java/direct_bt/tinyb/GattService.java (renamed from java/tinyb/hci/HCIGattService.java)30
-rw-r--r--java/direct_bt/tinyb/Manager.java (renamed from java/tinyb/hci/HCIManager.java)48
-rw-r--r--java/direct_bt/tinyb/NativeDownlink.java87
-rw-r--r--java/jni/BluetoothUtils.cxx53
-rw-r--r--java/jni/CMakeLists.txt38
-rw-r--r--java/jni/HCIManager.cxx30
-rw-r--r--java/jni/HCIObject.cxx34
-rw-r--r--java/jni/JNIMem.cxx31
-rw-r--r--java/jni/JNIMem.hpp28
-rw-r--r--java/jni/direct_bt/CMakeLists.txt53
-rw-r--r--java/jni/direct_bt/DBTAdapter.cxx259
-rw-r--r--java/jni/direct_bt/DBTDevice.cxx78
-rw-r--r--java/jni/direct_bt/DBTEvent.cxx (renamed from java/jni/HCIEvent.cxx)20
-rw-r--r--java/jni/direct_bt/DBTGattCharacteristic.cxx (renamed from java/jni/HCIGattCharacteristic.cxx)6
-rw-r--r--java/jni/direct_bt/DBTGattDescriptor.cxx (renamed from java/jni/HCIAdapter.cxx)6
-rw-r--r--java/jni/direct_bt/DBTGattService.cxx (renamed from java/jni/HCIGattDescriptor.cxx)6
-rw-r--r--java/jni/direct_bt/DBTManager.cxx106
-rw-r--r--java/jni/direct_bt/DBTNativeDownlink.cxx58
-rw-r--r--java/jni/direct_bt/DBTObject.cxx (renamed from java/jni/HCIGattService.cxx)6
-rw-r--r--java/jni/direct_bt/helper_dbt.cxx65
-rw-r--r--java/jni/direct_bt/helper_dbt.hpp113
-rw-r--r--java/jni/helper_base.cxx27
-rw-r--r--java/jni/helper_base.hpp68
-rw-r--r--java/jni/tinyb/CMakeLists.txt54
-rw-r--r--java/jni/tinyb/DBusAdapter.cxx (renamed from java/jni/DBusAdapter.cxx)0
-rw-r--r--java/jni/tinyb/DBusDevice.cxx (renamed from java/jni/DBusDevice.cxx)0
-rw-r--r--java/jni/tinyb/DBusEvent.cxx (renamed from java/jni/DBusEvent.cxx)0
-rw-r--r--java/jni/tinyb/DBusGattCharacteristic.cxx (renamed from java/jni/DBusGattCharacteristic.cxx)0
-rw-r--r--java/jni/tinyb/DBusGattDescriptor.cxx (renamed from java/jni/DBusGattDescriptor.cxx)0
-rw-r--r--java/jni/tinyb/DBusGattService.cxx (renamed from java/jni/DBusGattService.cxx)0
-rw-r--r--java/jni/tinyb/DBusManager.cxx (renamed from java/jni/DBusManager.cxx)0
-rw-r--r--java/jni/tinyb/DBusObject.cxx (renamed from java/jni/DBusObject.cxx)0
-rw-r--r--java/jni/tinyb/helper_tinyb.cxx (renamed from java/jni/helper_tinyb.cxx)36
-rw-r--r--java/jni/tinyb/helper_tinyb.hpp (renamed from java/jni/helper_tinyb.hpp)12
-rw-r--r--java/org/tinyb/BluetoothAdapter.java6
-rw-r--r--java/org/tinyb/BluetoothDeviceDiscoveryListener.java42
-rw-r--r--java/org/tinyb/BluetoothFactory.java10
-rw-r--r--java/org/tinyb/BluetoothManager.java9
-rw-r--r--java/org/tinyb/BluetoothUtils.java (renamed from java/jni/HCIDevice.cxx)16
-rw-r--r--java/tinyb/dbus/DBusAdapter.java6
-rw-r--r--java/tinyb/dbus/DBusManager.java5
-rw-r--r--java/tinyb/hci/HCIAdapter.java199
-rwxr-xr-xscripts/run-dbt_scanner.sh4
-rwxr-xr-xscripts/run-java-scanner.sh7
-rwxr-xr-xscripts/run-java-scanner00.sh7
-rwxr-xr-xscripts/run-java-scanner01.sh11
-rw-r--r--src/direct_bt/ATTPDUTypes.cpp2
-rw-r--r--src/direct_bt/BTTypes.cpp2
-rw-r--r--src/direct_bt/BasicTypes.cpp21
-rw-r--r--src/direct_bt/GATTHandler.cpp2
-rw-r--r--src/direct_bt/GATTNumbers.cpp2
-rw-r--r--src/direct_bt/GATTTypes.cpp2
-rw-r--r--src/direct_bt/HCIAdapter.cpp25
-rw-r--r--src/direct_bt/HCIComm.cpp3
-rw-r--r--src/direct_bt/HCIDevice.cpp4
-rw-r--r--src/direct_bt/L2CAPComm.cpp2
-rw-r--r--src/direct_bt/MgmtComm.cpp2
-rw-r--r--src/direct_bt/UUID.cpp2
75 files changed, 2286 insertions, 516 deletions
diff --git a/.cproject b/.cproject
index 4f664561..fecfa44a 100644
--- a/.cproject
+++ b/.cproject
@@ -79,7 +79,7 @@
<option id="gnu.cpp.compiler.option.pthread.956658404" name="Support for pthread (-pthread)" superClass="gnu.cpp.compiler.option.pthread" useByScannerDiscovery="false" value="true" valueType="boolean"/>
- <option id="gnu.cpp.compiler.option.warnings.extrawarn.602645664" superClass="gnu.cpp.compiler.option.warnings.extrawarn" useByScannerDiscovery="false" value="true" valueType="boolean"/>
+ <option id="gnu.cpp.compiler.option.warnings.extrawarn.602645664" name="Extra warnings (-Wextra)" superClass="gnu.cpp.compiler.option.warnings.extrawarn" useByScannerDiscovery="false" value="true" valueType="boolean"/>
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1946997217" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
@@ -109,7 +109,7 @@
<option id="gnu.c.compiler.option.pthread.858610172" name="Support for pthread (-pthread)" superClass="gnu.c.compiler.option.pthread" useByScannerDiscovery="false" value="true" valueType="boolean"/>
- <option id="gnu.c.compiler.option.warnings.extrawarn.1874778119" superClass="gnu.c.compiler.option.warnings.extrawarn" useByScannerDiscovery="false" value="true" valueType="boolean"/>
+ <option id="gnu.c.compiler.option.warnings.extrawarn.1874778119" name="Extra warnings (-Wextra)" superClass="gnu.c.compiler.option.warnings.extrawarn" useByScannerDiscovery="false" value="true" valueType="boolean"/>
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1736735651" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
@@ -175,6 +175,8 @@
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="include/cppunit"/>
+ <entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="java/jni"/>
+
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="src/direct_bt"/>
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="src/ieee11073"/>
diff --git a/api/direct_bt/BasicTypes.hpp b/api/direct_bt/BasicTypes.hpp
index 0da36a95..a626718d 100644
--- a/api/direct_bt/BasicTypes.hpp
+++ b/api/direct_bt/BasicTypes.hpp
@@ -59,6 +59,11 @@ namespace direct_bt {
virtual ~RuntimeException() noexcept { }
+ RuntimeException(const RuntimeException &o) = default;
+ RuntimeException(RuntimeException &&o) = default;
+ RuntimeException& operator=(const RuntimeException &o) = default;
+ RuntimeException& operator=(RuntimeException &&o) = default;
+
virtual const char* what() const noexcept override;
};
@@ -80,15 +85,9 @@ namespace direct_bt {
: RuntimeException("IllegalArgumentException", m, file, line) {}
};
- class IllegalStateException : public RuntimeException {
- public:
- IllegalStateException(std::string const m, const char* file, int line) noexcept
- : RuntimeException("IllegalStateException", m, file, line) {}
- };
-
class InvalidStateException : public RuntimeException {
public:
- InvalidStateException(std::string const m, const char* file, int line) noexcept
+ InvalidStateException(std::string const m, const char* file, int line) noexcept
: RuntimeException("InvalidStateException", m, file, line) {}
};
@@ -104,6 +103,15 @@ namespace direct_bt {
: RuntimeException("IndexOutOfBoundsException", "Index "+std::to_string(index)+", count "+std::to_string(count)+", data length "+std::to_string(length), file, line) {}
};
+ class BluetoothException : public RuntimeException {
+ public:
+ BluetoothException(std::string const m, const char* file, int line) noexcept
+ : RuntimeException("BluetoothException", m, file, line) {}
+
+ BluetoothException(const char *m, const char* file, int line) noexcept
+ : RuntimeException("BluetoothException", m, file, line) {}
+ };
+
/**
// *************************************************
// *************************************************
@@ -355,6 +363,7 @@ namespace direct_bt {
std::string uint8HexString(const uint8_t v, const bool leading0X);
std::string uint16HexString(const uint16_t v, const bool leading0X);
std::string uint32HexString(const uint32_t v, const bool leading0X);
+ std::string uint64HexString(const uint64_t v, const bool leading0X);
/**
* If lsbFirst is true, orders LSB left -> MSB right, usual for byte streams.
diff --git a/api/direct_bt/HCITypes.hpp b/api/direct_bt/HCITypes.hpp
index e7cb0384..17368aed 100644
--- a/api/direct_bt/HCITypes.hpp
+++ b/api/direct_bt/HCITypes.hpp
@@ -31,6 +31,7 @@
#include <memory>
#include <cstdint>
#include <vector>
+#include <functional>
#include <mutex>
#include <atomic>
@@ -40,6 +41,7 @@
#include "BTTypes.hpp"
#include "HCIComm.hpp"
#include "MgmtComm.hpp"
+#include "JavaAccess.hpp"
#define JAVA_MAIN_PACKAGE "org/tinyb"
#define JAVA_HCI_PACKAGE "tinyb/hci"
@@ -104,7 +106,7 @@ namespace direct_bt {
// *************************************************
// *************************************************
- class HCIObject
+ class HCIObject : public JavaUplink
{
protected:
std::mutex lk;
@@ -137,8 +139,11 @@ namespace direct_bt {
public:
virtual void deviceAdded(HCIAdapter const &a, std::shared_ptr<HCIDevice> device) = 0;
virtual void deviceUpdated(HCIAdapter const &a, std::shared_ptr<HCIDevice> device) = 0;
+ virtual void deviceRemoved(HCIAdapter const &a, std::shared_ptr<HCIDevice> device) = 0;
virtual ~HCIDeviceDiscoveryListener() {}
};
+ /** Alternative method to DeviceDiscoveryListener to set a callback */
+ typedef std::function<void(HCIAdapter const &a, std::shared_ptr<HCIDevice> device)> DeviceDiscoveryCallback;
class HCIDevice : public HCIObject
{
@@ -169,6 +174,13 @@ namespace direct_bt {
~HCIDevice();
+ std::string get_java_class() const override {
+ return java_class();
+ }
+ static std::string java_class() {
+ return std::string(JAVA_DBT_PACKAGE "Device");
+ }
+
/** Returns the managing adapter */
HCIAdapter const & getAdapter() const { return adapter; }
@@ -246,7 +258,7 @@ namespace direct_bt {
bool validateDevInfo();
friend bool HCISession::close();
- void sessionClosed(HCISession& s);
+ void sessionClosing(HCISession& s);
friend std::shared_ptr<HCIDevice> HCIDevice::getSharedInstance() const;
int findScannedDeviceIdx(EUI48 const & mac) const;
@@ -277,6 +289,13 @@ namespace direct_bt {
~HCIAdapter();
+ std::string get_java_class() const override {
+ return java_class();
+ }
+ static std::string java_class() {
+ return std::string(JAVA_DBT_PACKAGE "Adapter");
+ }
+
bool hasDevId() const { return 0 <= dev_id; }
EUI48 const & getAddress() const { return adapterInfo->mac; }
@@ -289,6 +308,11 @@ namespace direct_bt {
*/
std::shared_ptr<HCISession> open();
+ /**
+ * Returns the {@link #open()} session or {@code nullptr} if closed.
+ */
+ std::shared_ptr<HCISession> getOpenSession() { return session; }
+
// device discovery aka device scanning
/**
@@ -360,8 +384,8 @@ namespace direct_bt {
/** Returns discovered devices from a discovery */
std::vector<std::shared_ptr<HCIDevice>> getDiscoveredDevices() { return discoveredDevices; }
- /** Discards all discovered devices. */
- void removeDiscoveredDevices();
+ /** Discards all discovered devices. Returns number of removed discovered devices. */
+ int removeDiscoveredDevices();
/** Returns index >= 0 if found, otherwise -1 */
int findDiscoveredDeviceIdx(EUI48 const & mac) const;
diff --git a/api/direct_bt/JavaAccess.hpp b/api/direct_bt/JavaAccess.hpp
new file mode 100644
index 00000000..86c7251e
--- /dev/null
+++ b/api/direct_bt/JavaAccess.hpp
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef JAVA_ACCESS_HPP_
+#define JAVA_ACCESS_HPP_
+
+#include <string>
+#include <memory>
+
+namespace direct_bt {
+
+ #define JAVA_DBT_PACKAGE "direct_bt/tinyb/"
+
+ class JavaAnonObj {
+ public:
+ virtual ~JavaAnonObj() { }
+ virtual std::string toString() const { return "JavaAnonObj[???]"; }
+ };
+
+ class JavaUplink {
+ private:
+ std::shared_ptr<JavaAnonObj> javaObjectRef;
+
+ public:
+ virtual std::string toString() const = 0;
+ virtual std::string get_java_class() const = 0;
+
+ std::string javaObjectToString() const { return nullptr == javaObjectRef ? "JavaAnonObj[null]" : javaObjectRef->toString(); }
+
+ std::shared_ptr<JavaAnonObj> getJavaObject() { return javaObjectRef; }
+ void setJavaObject(std::shared_ptr<JavaAnonObj> objRef) { javaObjectRef = objRef; }
+
+ virtual ~JavaUplink() {
+ javaObjectRef = nullptr;
+ }
+ };
+
+} /* namespace direct_bt */
+
+
+#endif /* JAVA_ACCESS_HPP_ */
diff --git a/api/direct_bt/MgmtComm.hpp b/api/direct_bt/MgmtComm.hpp
index d7053273..a022a8d9 100644
--- a/api/direct_bt/MgmtComm.hpp
+++ b/api/direct_bt/MgmtComm.hpp
@@ -35,6 +35,7 @@
#include "BTIoctl.hpp"
#include "OctetTypes.hpp"
#include "HCIComm.hpp"
+#include "JavaAccess.hpp"
namespace direct_bt {
@@ -494,7 +495,7 @@ namespace direct_bt {
/**
* A thread safe singleton handler of the Linux Kernel's BlueZ manager control channel.
*/
- class MgmtHandler {
+ class MgmtHandler : public JavaUplink {
private:
std::recursive_mutex mtx;
const int ibuffer_size = 512;
@@ -535,6 +536,13 @@ namespace direct_bt {
}
~MgmtHandler() { close(); }
+ std::string get_java_class() const override {
+ return java_class();
+ }
+ static std::string java_class() {
+ return std::string(JAVA_DBT_PACKAGE "Manager");
+ }
+
/** Returns true if this mgmt instance is open and hence valid, otherwise false */
bool isOpen() const {
return comm.isOpen();
@@ -551,6 +559,8 @@ namespace direct_bt {
int getDefaultAdapterIdx() const { return adapters.size() > 0 ? 0 : -1; }
int findAdapterIdx(const EUI48 &mac) const;
std::shared_ptr<const AdapterInfo> getAdapter(const int idx) const;
+
+ std::string toString() const override { return "MgmtHandler["+std::to_string(adapters.size())+" adapter, "+javaObjectToString()+"]"; }
};
} // namespace direct_bt
diff --git a/src/direct_bt/dbt_debug.hpp b/api/direct_bt/dbt_debug.hpp
index f294b0ef..f294b0ef 100644
--- a/src/direct_bt/dbt_debug.hpp
+++ b/api/direct_bt/dbt_debug.hpp
diff --git a/examples/direct_bt_scanner/dbt_scanner.cpp b/examples/direct_bt_scanner/dbt_scanner.cpp
index dc245064..055aa7e1 100644
--- a/examples/direct_bt_scanner/dbt_scanner.cpp
+++ b/examples/direct_bt_scanner/dbt_scanner.cpp
@@ -47,6 +47,11 @@ class DeviceDiscoveryListener : public direct_bt::HCIDeviceDiscoveryListener {
fprintf(stderr, "Status HCIAdapter:\n");
fprintf(stderr, "%s\n", a.toString().c_str());
}
+ void deviceRemoved(direct_bt::HCIAdapter const &a, std::shared_ptr<direct_bt::HCIDevice> device) override {
+ fprintf(stderr, "****** REMOVED: %s\n", device->toString().c_str());
+ fprintf(stderr, "Status HCIAdapter:\n");
+ fprintf(stderr, "%s\n", a.toString().c_str());
+ }
};
static const uuid16_t _TEMPERATURE_MEASUREMENT(GattCharacteristicType::TEMPERATURE_MEASUREMENT);
diff --git a/examples/java/CMakeLists.txt b/examples/java/CMakeLists.txt
index a76b80b9..d8945755 100644
--- a/examples/java/CMakeLists.txt
+++ b/examples/java/CMakeLists.txt
@@ -22,9 +22,16 @@ add_custom_command(TARGET Notification
COMMAND cp "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/Notification.dir/Notification.class" "${CMAKE_CURRENT_BINARY_DIR}"
)
-add_jar(ScannerTinyB SOURCES ScannerTinyB.java INCLUDE_JARS "${CMAKE_CURRENT_BINARY_DIR}/../../java/tinyb2.jar" ENTRY_POINT Notification)
+add_jar(ScannerTinyB00 SOURCES ScannerTinyB00.java INCLUDE_JARS "${CMAKE_CURRENT_BINARY_DIR}/../../java/tinyb2.jar" ENTRY_POINT Notification)
-add_custom_command(TARGET ScannerTinyB
+add_custom_command(TARGET ScannerTinyB00
POST_BUILD
- COMMAND cp "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/ScannerTinyB.dir/ScannerTinyB.class" "${CMAKE_CURRENT_BINARY_DIR}"
+ COMMAND cp "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/ScannerTinyB00.dir/ScannerTinyB00.class" "${CMAKE_CURRENT_BINARY_DIR}"
+)
+
+add_jar(ScannerTinyB01 SOURCES ScannerTinyB01.java INCLUDE_JARS "${CMAKE_CURRENT_BINARY_DIR}/../../java/tinyb2.jar" ENTRY_POINT Notification)
+
+add_custom_command(TARGET ScannerTinyB01
+ POST_BUILD
+ COMMAND cp "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/ScannerTinyB01.dir/ScannerTinyB01.class" "${CMAKE_CURRENT_BINARY_DIR}"
)
diff --git a/examples/java/ScannerTinyB.java b/examples/java/ScannerTinyB00.java
index e3007d54..db9c2b38 100644
--- a/examples/java/ScannerTinyB.java
+++ b/examples/java/ScannerTinyB00.java
@@ -37,7 +37,7 @@ import org.tinyb.BluetoothGattService;
import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothNotification;
-public class ScannerTinyB {
+public class ScannerTinyB00 {
static {
System.setProperty("org.tinyb.verbose", "true");
}
diff --git a/examples/java/ScannerTinyB01.java b/examples/java/ScannerTinyB01.java
new file mode 100644
index 00000000..449ab765
--- /dev/null
+++ b/examples/java/ScannerTinyB01.java
@@ -0,0 +1,325 @@
+/**
+ * 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.
+ */
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Iterator;
+import java.util.List;
+
+import org.tinyb.BluetoothAdapter;
+import org.tinyb.BluetoothDevice;
+import org.tinyb.BluetoothDeviceDiscoveryListener;
+import org.tinyb.BluetoothException;
+import org.tinyb.BluetoothFactory;
+import org.tinyb.BluetoothGattCharacteristic;
+import org.tinyb.BluetoothGattDescriptor;
+import org.tinyb.BluetoothGattService;
+import org.tinyb.BluetoothManager;
+import org.tinyb.BluetoothNotification;
+import org.tinyb.BluetoothUtils;
+
+public class ScannerTinyB01 {
+ static {
+ System.setProperty("org.tinyb.verbose", "true");
+ }
+ /** 60,000 milliseconds */
+ static long TO_DISCOVER = 60000;
+
+ public static void main(final String[] args) throws InterruptedException {
+ String factoryImplClassName = BluetoothFactory.DirectBTFactoryImplClassName;
+ int mode = 0;
+ boolean forever = false;
+ final String mac;
+ {
+ String _mac = null;
+ for(int i=0; i< args.length; i++) {
+ final String arg = args[i];
+
+ if( arg.equals("-mac") ) {
+ _mac = args[++i];
+ } else if( arg.equals("-mode") ) {
+ mode = Integer.valueOf(args[++i]).intValue();
+ } else if( arg.equals("-factory") ) {
+ factoryImplClassName = args[++i];
+ } else if( arg.equals("-forever") ) {
+ forever = true;
+ }
+ }
+
+ if ( null == _mac ) {
+ System.err.println("Run with '-mac <device_address> [-mode <mode>] [-factory <BluetoothManager-Factory-Implementation-Class>]'");
+ System.exit(-1);
+ }
+ mac = _mac;
+ }
+
+ final BluetoothManager manager;
+ {
+ BluetoothManager _manager = null;
+ try {
+ _manager = BluetoothFactory.getBluetoothManager(factoryImplClassName);
+ } catch (BluetoothException | NoSuchMethodException | SecurityException
+ | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException | ClassNotFoundException e) {
+ System.err.println("Unable to instantiate BluetoothManager via factory "+factoryImplClassName);
+ e.printStackTrace();
+ System.exit(-1);
+ }
+ manager = _manager;
+ }
+ final BluetoothAdapter adapter = manager.getDefaultAdapter();
+ final BluetoothDevice[] matchingDiscoveredDeviceBucket = { null };
+
+ final BluetoothDeviceDiscoveryListener deviceDiscListener = new BluetoothDeviceDiscoveryListener() {
+ @Override
+ public void deviceAdded(final BluetoothAdapter adapter, final BluetoothDevice device) {
+ final boolean matches = device.getAddress().equals(mac);
+ System.err.println("****** ADDED__: "+device.toString()+" - match "+matches);
+ System.err.println("Status HCIAdapter:");
+ System.err.println(adapter.toString());
+
+ if( matches ) {
+ synchronized(matchingDiscoveredDeviceBucket) {
+ matchingDiscoveredDeviceBucket[0] = device;
+ matchingDiscoveredDeviceBucket.notifyAll();
+ }
+ }
+ }
+
+ @Override
+ public void deviceUpdated(final BluetoothAdapter adapter, final BluetoothDevice device) {
+ final boolean matches = device.getAddress().equals(mac);
+ System.err.println("****** UPDATED: "+device.toString()+" - match "+matches);
+ System.err.println("Status HCIAdapter:");
+ System.err.println(adapter.toString());
+ }
+
+ @Override
+ public void deviceRemoved(final BluetoothAdapter adapter, final BluetoothDevice device) {
+ final boolean matches = device.getAddress().equals(mac);
+ System.err.println("****** REMOVED: "+device.toString()+" - match "+matches);
+ System.err.println("Status HCIAdapter:");
+ System.err.println(adapter.toString());
+ }
+ };
+ adapter.setDeviceDiscoveryListener(deviceDiscListener);
+
+
+ do {
+ final long t0 = BluetoothUtils.getCurrentMilliseconds();
+
+ adapter.removeDevices();
+ final boolean discoveryStarted = adapter.startDiscovery();
+
+ System.err.println("The discovery started: " + (discoveryStarted ? "true" : "false") + " for mac "+mac+", mode "+mode);
+ if( !discoveryStarted ) {
+ break;
+ }
+ BluetoothDevice sensor = null;
+
+ if( 0 == mode ) {
+ synchronized(matchingDiscoveredDeviceBucket) {
+ while( null == matchingDiscoveredDeviceBucket[0] ) {
+ matchingDiscoveredDeviceBucket.wait(TO_DISCOVER);
+ }
+ sensor = matchingDiscoveredDeviceBucket[0];
+ }
+ } else if( 1 == mode ) {
+ sensor = adapter.find(null, mac, TO_DISCOVER);
+ } else {
+ boolean timeout = false;
+ while( null == sensor && !timeout ) {
+ final List<BluetoothDevice> devices = adapter.getDevices();
+ for(final Iterator<BluetoothDevice> id = devices.iterator(); id.hasNext() && !timeout; ) {
+ final BluetoothDevice d = id.next();
+ if(d.getAddress().equals(mac)) {
+ sensor = d;
+ break;
+ }
+ final long tn = BluetoothUtils.getCurrentMilliseconds();
+ timeout = ( tn - t0 ) > TO_DISCOVER;
+ }
+ }
+ }
+ final long t1 = BluetoothUtils.getCurrentMilliseconds();
+ if (sensor == null) {
+ System.err.println("No sensor found within "+(t1-t0)+" ms");
+ System.exit(-1);
+ }
+ System.err.println("Found device in "+(t1-t0)+" ms: ");
+ printDevice(sensor);
+ System.err.println("ScannerTinyB01 01 stopDiscovery: "+adapter);
+ adapter.stopDiscovery();
+ System.err.println("ScannerTinyB01 02 close: "+adapter);
+ adapter.close();
+ System.err.println("ScannerTinyB01 03 ...: "+adapter);
+
+ if(false) {
+ final BooleanNotification connectedNotification = new BooleanNotification("Connected", t1);
+ final BooleanNotification servicesResolvedNotification = new BooleanNotification("ServicesResolved", t1);
+ sensor.enableConnectedNotifications(connectedNotification);
+ sensor.enableServicesResolvedNotifications(servicesResolvedNotification);
+
+ final long t2;
+ if ( sensor.connect() ) {
+ t2 = BluetoothUtils.getCurrentMilliseconds();
+ System.err.println("Sensor connected in "+(t2-t1)+" ms");
+ System.err.println("Sensor connectedNotification: "+connectedNotification.getValue());
+ } else {
+ t2=0;
+ System.out.println("Could not connect device.");
+ System.exit(-1);
+ }
+
+ synchronized( servicesResolvedNotification ) {
+ while( !servicesResolvedNotification.getValue() ) {
+ final long tn = BluetoothUtils.getCurrentMilliseconds();
+ if( tn - t2 > 20000 ) {
+ break; // 20s TO
+ }
+ servicesResolvedNotification.wait();
+ }
+ }
+ final long t3;
+ if ( servicesResolvedNotification.getValue() ) {
+ t3 = BluetoothUtils.getCurrentMilliseconds();
+ System.err.println("Sensor servicesResolved in "+(t3-t2)+" ms, total "+(t3-t1)+" ms");
+ } else {
+ t3=0;
+ System.out.println("Could not connect device.");
+ System.exit(-1);
+ }
+ // Will shut down everything .. ??
+ //adapter.stopDiscovery();
+
+ final List<BluetoothGattService> allBluetoothServices = sensor.getServices();
+ if (allBluetoothServices.isEmpty()) {
+ System.err.println("No BluetoothGattService found!");
+ System.exit(1);
+ }
+ printAllServiceInfo(allBluetoothServices);
+
+ sensor.disconnect();
+ }
+ System.err.println("ScannerTinyB01 04 ...: "+adapter);
+ } while( forever );
+ System.err.println("ScannerTinyB01 05");
+ manager.shutdown();
+ System.err.println("ScannerTinyB01 XX");
+ }
+ private static void printDevice(final BluetoothDevice device) {
+ System.err.println("Address = " + device.getAddress());
+ System.err.println(" Name = " + device.getName());
+ System.err.println(" Connected = " + device.getConnected());
+ System.err.println();
+ }
+ private static void printAllServiceInfo(final List<BluetoothGattService> allBluetoothServices) {
+ try {
+ for (final BluetoothGattService service : allBluetoothServices) {
+ System.err.println("Service UUID: " + service.getUUID());
+ final List<BluetoothGattCharacteristic> v = service.getCharacteristics();
+ for (final BluetoothGattCharacteristic c : v) {
+ System.err.println(" Characteristic UUID: " + c.getUUID());
+
+ final List<BluetoothGattDescriptor> descriptors = c.getDescriptors();
+
+ for (final BluetoothGattDescriptor d : descriptors) {
+ System.err.println(" Descriptor UUID: " + d.getUUID());
+ }
+ if (c.getUUID().contains("2a29-")) {
+ final byte[] tempRaw = c.readValue();
+ System.err.println(" Manufacturer: " + new String(tempRaw));
+ }
+
+ if (c.getUUID().contains("2a28-")) {
+ final byte[] tempRaw = c.readValue();
+ System.err.println(" Software: " + new String(tempRaw));
+ }
+
+ if (c.getUUID().contains("2a27-")) {
+ final byte[] tempRaw = c.readValue();
+ System.err.println(" Hardware: " + new String(tempRaw));
+ }
+
+ if (c.getUUID().contains("2a26-")) {
+ final byte[] tempRaw = c.readValue();
+ System.err.println(" Firmware: " + new String(tempRaw));
+ }
+
+ if (c.getUUID().contains("2a25-")) {
+ final byte[] tempRaw = c.readValue();
+ System.err.println(" Serial: " + new String(tempRaw));
+ }
+
+ if (c.getUUID().contains("2a24-")) {
+ final byte[] tempRaw = c.readValue();
+ System.err.println(" Model: " + new String(tempRaw));
+ }
+
+ if (c.getUUID().contains("2a23-")) {
+ final byte[] tempRaw = c.readValue();
+ System.err.println(" System ID: " + bytesToHex(tempRaw));
+ }
+ }
+ }
+ } catch (final RuntimeException e) {
+ }
+ }
+ private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+ public static String bytesToHex(final byte[] bytes) {
+ final char[] hexChars = new char[bytes.length * 2];
+ for (int j = 0; j < bytes.length; j++) {
+ final int v = bytes[j] & 0xFF;
+ hexChars[j * 2] = HEX_ARRAY[v >>> 4];
+ hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+ static class BooleanNotification implements BluetoothNotification<Boolean> {
+ private final long t0;
+ private final String name;
+ private boolean v;
+
+ public BooleanNotification(final String name, final long t0) {
+ this.t0 = t0;
+ this.name = name;
+ this.v = false;
+ }
+
+ @Override
+ public void run(final Boolean v) {
+ synchronized(this) {
+ final long t1 = BluetoothUtils.getCurrentMilliseconds();
+ this.v = v.booleanValue();
+ System.out.println("#### "+name+": "+v+" in td "+(t1-t0)+" ms!");
+ this.notifyAll();
+ }
+ }
+ public boolean getValue() {
+ synchronized(this) {
+ return v;
+ }
+ }
+ }
+}
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index 1f3b1771..ba7c017b 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -27,4 +27,5 @@ add_custom_command (TARGET tinybjar
set(JNI_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/tinybjar.dir/jni")
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/tinyb2.jar DESTINATION ${CMAKE_INSTALL_LIBDIR}/../lib/java)
-add_subdirectory (jni)
+add_subdirectory (jni/direct_bt)
+add_subdirectory (jni/tinyb)
diff --git a/java/direct_bt/tinyb/Adapter.java b/java/direct_bt/tinyb/Adapter.java
new file mode 100644
index 00000000..b953c318
--- /dev/null
+++ b/java/direct_bt/tinyb/Adapter.java
@@ -0,0 +1,417 @@
+/**
+ * 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.
+ */
+
+package direct_bt.tinyb;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.tinyb.BluetoothAdapter;
+import org.tinyb.BluetoothDevice;
+import org.tinyb.BluetoothException;
+import org.tinyb.BluetoothManager;
+import org.tinyb.BluetoothNotification;
+import org.tinyb.BluetoothType;
+import org.tinyb.BluetoothDeviceDiscoveryListener;
+import org.tinyb.TransportType;
+
+public class Adapter extends DBTObject implements BluetoothAdapter
+{
+ private final String address;
+ private final String name;
+ private final DiscoveryThread discoveryThread;
+
+ /* pp */ Adapter(final long nativeInstance, final String address, final String name)
+ {
+ super(nativeInstance, compHash(address, name));
+ this.address = address;
+ this.name = name;
+ this.discoveryThread = new DiscoveryThread();
+ this.discoveryThread.start(null);
+ initImpl(this.discoveryThread.deviceDiscoveryListener);
+ }
+
+ @Override
+ public synchronized void close() {
+ discoveryThread.stop();
+ super.close();
+ }
+
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (obj == null || !(obj instanceof Device)) {
+ return false;
+ }
+ final Adapter other = (Adapter)obj;
+ return address.equals(other.address) && name.equals(other.name);
+ }
+
+ @Override
+ public String getAddress() { return address; }
+
+ @Override
+ public String getName() { return name; }
+
+ public String getInterfaceName() {
+ throw new UnsupportedOperationException(); // FIXME
+ }
+
+ @Override
+ public BluetoothType getBluetoothType() { return class_type(); }
+
+ static BluetoothType class_type() { return BluetoothType.ADAPTER; }
+
+ @Override
+ public final BluetoothAdapter clone()
+ { throw new UnsupportedOperationException(); } // FIXME
+
+ @Override
+ public BluetoothDevice find(final String name, final String address, final long timeoutMS) {
+ final BluetoothManager manager = Manager.getBluetoothManager();
+ return (BluetoothDevice) manager.find(BluetoothType.DEVICE, name, address, this, timeoutMS);
+ }
+
+ @Override
+ public BluetoothDevice find(final String name, final String address) {
+ return find(name, address, 0);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder out = new StringBuilder();
+ out.append("Adapter[").append(getAddress()).append(", '").append(getName()).append("', id=").append("]");
+ synchronized(discoveryThread.discoveredDevicesLock) {
+ final int count = discoveryThread.discoveredDevices.size();
+ if( count > 0 ) {
+ out.append("\n");
+ for(final Iterator<BluetoothDevice> iter=discoveryThread.discoveredDevices.iterator(); iter.hasNext(); ) {
+ final BluetoothDevice device = iter.next();
+ out.append(" ").append(device.toString()).append("\n");
+ }
+ }
+ }
+ return out.toString();
+ }
+
+ /* property accessors: */
+
+ @Override
+ public String getAlias() { throw new UnsupportedOperationException(); } // FIXME
+
+ @Override
+ public void setAlias(final String value) { throw new UnsupportedOperationException(); } // FIXME
+
+ @Override
+ public long getBluetoothClass() { throw new UnsupportedOperationException(); } // FIXME
+
+ @Override
+ public native boolean getPowered();
+
+ @Override
+ public native void enablePoweredNotifications(BluetoothNotification<Boolean> callback);
+
+ @Override
+ public native void disablePoweredNotifications();
+
+ @Override
+ public native void setPowered(boolean value);
+
+ @Override
+ public native boolean getDiscoverable();
+
+ @Override
+ public native void enableDiscoverableNotifications(BluetoothNotification<Boolean> callback);
+
+ @Override
+ public native void disableDiscoverableNotifications();
+
+ @Override
+ public native void setDiscoverable(boolean value);
+
+ @Override
+ public native long getDiscoverableTimeout();
+
+ @Override
+ public native void setDiscoverableTimout(long value);
+
+ @Override
+ public native BluetoothDevice connectDevice(String address, String addressType);
+
+ @Override
+ public native boolean getPairable();
+
+ @Override
+ public native void enablePairableNotifications(BluetoothNotification<Boolean> callback);
+
+ @Override
+ public native void disablePairableNotifications();
+
+ @Override
+ public native void setPairable(boolean value);
+
+ @Override
+ public native long getPairableTimeout();
+
+ @Override
+ public native void setPairableTimeout(long value);
+
+ @Override
+ public native String[] getUUIDs();
+
+ @Override
+ public native String getModalias();
+
+ /* internal */
+
+ private native void initImpl(final BluetoothDeviceDiscoveryListener l);
+
+ @Override
+ protected native void deleteImpl();
+
+ /* discovery */
+
+ @Override
+ public boolean startDiscovery() throws BluetoothException {
+ return discoveryThread.doDiscovery(true);
+ }
+ private native boolean startDiscoveryImpl() throws BluetoothException;
+
+ @Override
+ public boolean stopDiscovery() throws BluetoothException {
+ return discoveryThread.doDiscovery(false);
+ }
+ private native boolean stopDiscoveryImpl() throws BluetoothException;
+
+ @Override
+ public List<BluetoothDevice> getDevices() {
+ return discoveryThread.getDiscoveredDevices();
+ }
+
+ @Override
+ public int removeDevices() throws BluetoothException {
+ final int cj = discoveryThread.removeDiscoveredDevices();
+ final int cn = removeDevicesImpl();
+ if( cj != cn ) {
+ throw new InternalError("Inconsistent discovered device count: Native "+cn+", callback "+cj);
+ }
+ return cn;
+ }
+ private native int removeDevicesImpl() throws BluetoothException;
+
+ @Override
+ public boolean getDiscovering() { return discoveryThread.running && discoveryThread.doDiscovery; }
+
+ @Override
+ public void setDeviceDiscoveryListener(final BluetoothDeviceDiscoveryListener l) {
+ discoveryThread.setDeviceDiscoveryListener(l);
+ }
+
+ @Override
+ public void enableDiscoveringNotifications(final BluetoothNotification<Boolean> callback) {
+ discoveryThread.setDiscoveringNotificationCallback(callback);
+ }
+
+ @Override
+ public void disableDiscoveringNotifications() {
+ discoveryThread.setDiscoveringNotificationCallback(null);
+ }
+
+ @Override
+ public void setDiscoveryFilter(final List<UUID> uuids, final int rssi, final int pathloss, final TransportType transportType) {
+ final List<String> uuidsFmt = new ArrayList<>(uuids.size());
+ for (final UUID uuid : uuids) {
+ uuidsFmt.add(uuid.toString());
+ }
+ setDiscoveryFilter(uuidsFmt, rssi, pathloss, transportType.ordinal());
+ }
+
+ public void setRssiDiscoveryFilter(final int rssi) {
+ setDiscoveryFilter(Collections.EMPTY_LIST, rssi, 0, TransportType.AUTO);
+ }
+
+ private native void setDiscoveryFilter(List<String> uuids, int rssi, int pathloss, int transportType);
+
+ private native int discoverAnyDeviceImpl(final int timeoutMS) throws BluetoothException;
+ // std::vector<std::shared_ptr<direct_bt::HCIDevice>> discoveredDevices = adapter.getDiscoveredDevices();
+ private native List<BluetoothDevice> getDiscoveredDevicesImpl();
+
+ private class DiscoveryThread implements Runnable {
+ private int instanceID=-1;
+
+ private volatile boolean running = false;
+ private volatile boolean doDiscovery = false;
+ private final Object stateLock = new Object();
+ private volatile BluetoothDeviceDiscoveryListener userDeviceDiscoveryListener = null;
+ private volatile BluetoothNotification<Boolean> discoveringNotificationCB = null;
+ private List<BluetoothDevice> discoveredDevices = new ArrayList<BluetoothDevice>();
+ private final Object discoveredDevicesLock = new Object();
+
+ private final BluetoothDeviceDiscoveryListener deviceDiscoveryListener = new BluetoothDeviceDiscoveryListener() {
+ @Override
+ public void deviceAdded(final BluetoothAdapter a, final BluetoothDevice device) {
+ final BluetoothDeviceDiscoveryListener l = userDeviceDiscoveryListener;
+ System.err.println("DBTAdapter.DeviceDiscoveryListener.added: "+device+" on "+a);
+ synchronized(discoveredDevicesLock) {
+ discoveredDevices.add(device);
+ }
+ if( null != l ) {
+ l.deviceAdded(a, device);
+ }
+ }
+
+ @Override
+ public void deviceUpdated(final BluetoothAdapter a, final BluetoothDevice device) {
+ System.err.println("DBTAdapter.DeviceDiscoveryListener.updated: "+device+" on "+a);
+ // nop on discoveredDevices
+ userDeviceDiscoveryListener.deviceUpdated(a, device);
+ }
+
+ @Override
+ public void deviceRemoved(final BluetoothAdapter a, final BluetoothDevice device) {
+ final BluetoothDeviceDiscoveryListener l = userDeviceDiscoveryListener;
+ System.err.println("DBTAdapter.DeviceDiscoveryListener.removed: "+device+" on "+a);
+ synchronized(discoveredDevicesLock) {
+ discoveredDevices.remove(device);
+ }
+ if( null != l ) {
+ l.deviceRemoved(a, device);
+ }
+ }
+ };
+
+ public void start(final ThreadGroup tg) {
+ synchronized( stateLock ) {
+ if ( !running ) {
+ instanceID = globThreadID.addAndGet(1);
+ final Thread t = new Thread(tg, this, "Adapter-"+instanceID); // Thread name aligned w/ 'Thread-#'
+ t.setDaemon(true);
+ t.start();
+ while( !running ) {
+ try {
+ stateLock.wait();
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ public void setDeviceDiscoveryListener(final BluetoothDeviceDiscoveryListener l) {
+ synchronized( stateLock ) {
+ userDeviceDiscoveryListener = l;
+ stateLock.notifyAll();
+ }
+ }
+ public void setDiscoveringNotificationCallback(final BluetoothNotification<Boolean> cb) {
+ synchronized( stateLock ) {
+ discoveringNotificationCB = cb;
+ stateLock.notifyAll();
+ }
+ }
+ public List<BluetoothDevice> getDiscoveredDevices() {
+ synchronized(discoveredDevicesLock) {
+ return new ArrayList<BluetoothDevice>(discoveredDevices);
+ }
+ }
+ public int removeDiscoveredDevices() {
+ synchronized(discoveredDevicesLock) {
+ final int n = discoveredDevices.size();
+ discoveredDevices = new ArrayList<BluetoothDevice>();
+ return n;
+ }
+ }
+ public boolean doDiscovery(final boolean v) {
+ synchronized( stateLock ) {
+ if( v == doDiscovery ) {
+ return v;
+ }
+ final BluetoothNotification<Boolean> cb = discoveringNotificationCB;
+ final boolean enable;
+ if( v ) {
+ enable = startDiscoveryImpl();
+ } else {
+ enable = false;
+ stopDiscoveryImpl();
+ }
+ doDiscovery = enable;
+ if( null != cb ) {
+ cb.run(enable);
+ }
+ stateLock.notifyAll();
+ return enable;
+ }
+ }
+ public void stop() {
+ synchronized( stateLock ) {
+ stopDiscoveryImpl();
+ running = false;
+ doDiscovery = false;
+ stateLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void run() {
+ synchronized( stateLock ) {
+ running = true;
+ stateLock.notifyAll();
+ }
+ while (running) {
+ synchronized( stateLock ) {
+ while( running && !doDiscovery ) {
+ try {
+ stateLock.wait();
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ if( !running ) {
+ break; // end loop and thread
+ }
+
+ try {
+ if( doDiscovery ) {
+ // will trigger all discovery callbacks!
+ discoverAnyDeviceImpl(discoverTimeoutMS);
+ }
+ } catch (final Exception e) {
+ System.err.println(e.toString());
+ e.printStackTrace();
+ doDiscovery = false;
+ }
+ } // loop
+
+ instanceID = -1;
+ }
+ }
+ private static AtomicInteger globThreadID = new AtomicInteger(0);
+ private static int discoverTimeoutMS = 100;
+}
diff --git a/java/tinyb/hci/HCIEvent.java b/java/direct_bt/tinyb/DBTEvent.java
index 4dc30ec3..66317ea9 100644
--- a/java/tinyb/hci/HCIEvent.java
+++ b/java/direct_bt/tinyb/DBTEvent.java
@@ -23,13 +23,13 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-package tinyb.hci;
+package direct_bt.tinyb;
import org.tinyb.BluetoothCallback;
import org.tinyb.BluetoothEvent;
import org.tinyb.BluetoothType;
-public class HCIEvent implements BluetoothEvent
+public class DBTEvent implements BluetoothEvent
{
private long nativeInstance;
@@ -45,11 +45,11 @@ public class HCIEvent implements BluetoothEvent
public native boolean hasCallback();
private native void init(BluetoothType type, String name, String identifier,
- HCIObject parent, BluetoothCallback cb, Object data);
+ DBTObject parent, BluetoothCallback cb, Object data);
private native void delete();
- public HCIEvent(final BluetoothType type, final String name, final String identifier,
- final HCIObject parent, final BluetoothCallback cb, final Object data)
+ public DBTEvent(final BluetoothType type, final String name, final String identifier,
+ final DBTObject parent, final BluetoothCallback cb, final Object data)
{
init(type, name, identifier, parent, cb, data);
}
diff --git a/java/tinyb/hci/HCIObject.java b/java/direct_bt/tinyb/DBTObject.java
index 85a903e5..93b10245 100644
--- a/java/tinyb/hci/HCIObject.java
+++ b/java/direct_bt/tinyb/DBTObject.java
@@ -23,28 +23,14 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-package tinyb.hci;
+package direct_bt.tinyb;
-import org.tinyb.BluetoothFactory;
import org.tinyb.BluetoothObject;
import org.tinyb.BluetoothType;
-public abstract class HCIObject implements BluetoothObject
+public abstract class DBTObject extends NativeDownlink implements BluetoothObject
{
private final int hashValue;
- private boolean isValid;
-
- static {
- try {
- System.loadLibrary(BluetoothFactory.JavaNativeLibBasename);
- } catch (final Throwable e) {
- System.err.println("Failed to load native library "+BluetoothFactory.JavaNativeLibBasename);
- e.printStackTrace();
- throw e; // fwd exception - end here
- }
- }
-
- static BluetoothType class_type() { return BluetoothType.NONE; }
/* pp */ static int compHash(final String a, final String b) {
// 31 * x == (x << 5) - x
@@ -52,12 +38,14 @@ public abstract class HCIObject implements BluetoothObject
return ((hash << 5) - hash) + b.hashCode();
}
- protected HCIObject(final int hashValue)
+ protected DBTObject(final long nativeInstance, final int hashValue)
{
+ super(nativeInstance);
this.hashValue = hashValue;
- isValid = true;
}
+ static BluetoothType class_type() { return BluetoothType.NONE; }
+
@Override
public abstract boolean equals(final Object obj);
@@ -74,18 +62,11 @@ public abstract class HCIObject implements BluetoothObject
@Override
public synchronized void close() {
- if (!isValid) {
- return;
- }
- isValid = false;
delete();
}
- @Override
- public native BluetoothType getBluetoothType();
@Override
public BluetoothObject clone()
{ throw new UnsupportedOperationException(); } // FIXME
- private native void delete();
}
diff --git a/java/tinyb/hci/HCIDevice.java b/java/direct_bt/tinyb/Device.java
index b9a41a53..f3a90d6b 100644
--- a/java/tinyb/hci/HCIDevice.java
+++ b/java/direct_bt/tinyb/Device.java
@@ -23,7 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-package tinyb.hci;
+package direct_bt.tinyb;
import java.util.List;
import java.util.Map;
@@ -34,30 +34,34 @@ import org.tinyb.BluetoothGattService;
import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothNotification;
import org.tinyb.BluetoothType;
+import org.tinyb.BluetoothUtils;
-import tinyb.dbus.DBusObject;
-
-public class HCIDevice extends HCIObject implements BluetoothDevice
+public class Device extends DBTObject implements BluetoothDevice
{
- private final HCIAdapter adapter;
+ private final Adapter adapter;
private final String address;
private final String name;
+ private final long ts_creation;
+ long ts_update;
- /* pp */ HCIDevice(final HCIAdapter adptr, final String address, final String name)
+ /* pp */ Device(final long nativeInstance, final Adapter adptr, final String address, final String name, final long ts_creation)
{
- super(compHash(address, name));
+ super(nativeInstance, compHash(address, name));
this.adapter = adptr;
this.address = address;
this.name = name;
+ this.ts_creation = ts_creation;
+ ts_update = ts_creation;
+ initImpl();
}
@Override
public boolean equals(final Object obj)
{
- if (obj == null || !(obj instanceof HCIDevice)) {
+ if (obj == null || !(obj instanceof Device)) {
return false;
}
- final HCIDevice other = (HCIDevice)obj;
+ final Device other = (Device)obj;
return address.equals(other.address) && name.equals(other.name);
}
@@ -70,14 +74,15 @@ public class HCIDevice extends HCIObject implements BluetoothDevice
@Override
public BluetoothType getBluetoothType() { return class_type(); }
- @Override
- public native HCIDevice clone();
-
static BluetoothType class_type() { return BluetoothType.DEVICE; }
@Override
+ public final BluetoothDevice clone()
+ { throw new UnsupportedOperationException(); } // FIXME
+
+ @Override
public BluetoothGattService find(final String UUID, final long timeoutMS) {
- final BluetoothManager manager = HCIManager.getBluetoothManager();
+ final BluetoothManager manager = Manager.getBluetoothManager();
return (BluetoothGattService) manager.find(BluetoothType.GATT_SERVICE,
null, UUID, this, timeoutMS);
}
@@ -87,6 +92,34 @@ public class HCIDevice extends HCIObject implements BluetoothDevice
return find(UUID, 0);
}
+ @Override
+ public String toString() {
+ final StringBuilder out = new StringBuilder();
+ final long t0 = BluetoothUtils.getCurrentMilliseconds();
+ // std::string msdstr = nullptr != msd ? msd->toString() : "MSD[null]";
+ final String msdstr = "MSD[null]";
+ out.append("Device[").append(getAddress()).append(", '").append(getName())
+ .append("', age ").append(t0-ts_creation).append(" ms, lup ").append(t0-ts_update).append(" ms, rssi ").append(getRSSI())
+ .append(", tx-power ").append(getTxPower()).append(", ").append(msdstr).append("]");
+ /**
+ if(services.size() > 0 ) {
+ out.append("\n");
+ final int i=0;
+ for(final auto it = services.begin(); it != services.end(); it++, i++) {
+ if( 0 < i ) {
+ out.append("\n");
+ }
+ std::shared_ptr<uuid_t> p = *it;
+ out.append(" ").append(p->toUUID128String()).append(", ").append(std::to_string(static_cast<int>(p->getTypeSize()))).append(" bytes");
+ }
+ } */
+ return out.toString();
+ }
+
+ /* internal */
+
+ private native void initImpl();
+
/* D-Bus method calls: */
@Override
@@ -194,7 +227,7 @@ public class HCIDevice extends HCIObject implements BluetoothDevice
public native String getModalias();
@Override
- public native HCIAdapter getAdapter();
+ public native Adapter getAdapter();
@Override
public native Map<Short, byte[]> getManufacturerData();
@@ -227,5 +260,6 @@ public class HCIDevice extends HCIObject implements BluetoothDevice
@Override
public native void disableServicesResolvedNotifications();
- private native void delete();
+ @Override
+ protected native void deleteImpl();
}
diff --git a/java/tinyb/hci/HCIGattCharacteristic.java b/java/direct_bt/tinyb/GattCharacteristic.java
index a2047e1e..801dac33 100644
--- a/java/tinyb/hci/HCIGattCharacteristic.java
+++ b/java/direct_bt/tinyb/GattCharacteristic.java
@@ -23,10 +23,11 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-package tinyb.hci;
+package direct_bt.tinyb;
import java.util.List;
+import org.tinyb.BluetoothDevice;
import org.tinyb.BluetoothException;
import org.tinyb.BluetoothGattCharacteristic;
import org.tinyb.BluetoothGattDescriptor;
@@ -35,23 +36,23 @@ import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothNotification;
import org.tinyb.BluetoothType;
-public class HCIGattCharacteristic extends HCIObject implements BluetoothGattCharacteristic
+public class GattCharacteristic extends DBTObject implements BluetoothGattCharacteristic
{
private final String uuid;
- /* pp */ HCIGattCharacteristic(final String uuid)
+ /* pp */ GattCharacteristic(final long nativeInstance, final String uuid)
{
- super(uuid.hashCode());
+ super(nativeInstance, uuid.hashCode());
this.uuid = uuid;
}
@Override
public boolean equals(final Object obj)
{
- if (obj == null || !(obj instanceof HCIGattCharacteristic)) {
+ if (obj == null || !(obj instanceof GattCharacteristic)) {
return false;
}
- final HCIGattCharacteristic other = (HCIGattCharacteristic)obj;
+ final GattCharacteristic other = (GattCharacteristic)obj;
return uuid.equals(other.uuid);
}
@@ -59,15 +60,17 @@ public class HCIGattCharacteristic extends HCIObject implements BluetoothGattCha
public String getUUID() { return uuid; }
@Override
- public native BluetoothType getBluetoothType();
- @Override
- public native HCIGattCharacteristic clone();
+ public BluetoothType getBluetoothType() { return class_type(); }
static BluetoothType class_type() { return BluetoothType.GATT_CHARACTERISTIC; }
@Override
+ public final GattCharacteristic clone()
+ { throw new UnsupportedOperationException(); } // FIXME
+
+ @Override
public BluetoothGattDescriptor find(final String UUID, final long timeoutMS) {
- final BluetoothManager manager = HCIManager.getBluetoothManager();
+ final BluetoothManager manager = Manager.getBluetoothManager();
return (BluetoothGattDescriptor) manager.find(BluetoothType.GATT_DESCRIPTOR,
null, UUID, this, timeoutMS);
}
@@ -108,8 +111,9 @@ public class HCIGattCharacteristic extends HCIObject implements BluetoothGattCha
@Override
public native List<BluetoothGattDescriptor> getDescriptors();
- private native void init(HCIGattCharacteristic obj);
+ private native void init(GattCharacteristic obj);
- private native void delete();
+ @Override
+ protected native void deleteImpl();
}
diff --git a/java/tinyb/hci/HCIGattDescriptor.java b/java/direct_bt/tinyb/GattDescriptor.java
index b04816a4..5b0d2898 100644
--- a/java/tinyb/hci/HCIGattDescriptor.java
+++ b/java/direct_bt/tinyb/GattDescriptor.java
@@ -23,30 +23,30 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-package tinyb.hci;
+package direct_bt.tinyb;
import org.tinyb.BluetoothException;
import org.tinyb.BluetoothGattDescriptor;
import org.tinyb.BluetoothNotification;
import org.tinyb.BluetoothType;
-public class HCIGattDescriptor extends HCIObject implements BluetoothGattDescriptor
+public class GattDescriptor extends DBTObject implements BluetoothGattDescriptor
{
private final String uuid;
- /* pp */ HCIGattDescriptor(final String uuid)
+ /* pp */ GattDescriptor(final long nativeInstance, final String uuid)
{
- super(uuid.hashCode());
+ super(nativeInstance, uuid.hashCode());
this.uuid = uuid;
}
@Override
public boolean equals(final Object obj)
{
- if (obj == null || !(obj instanceof HCIGattDescriptor)) {
+ if (obj == null || !(obj instanceof GattDescriptor)) {
return false;
}
- final HCIGattDescriptor other = (HCIGattDescriptor)obj;
+ final GattDescriptor other = (GattDescriptor)obj;
return uuid.equals(other.uuid);
}
@@ -54,12 +54,14 @@ public class HCIGattDescriptor extends HCIObject implements BluetoothGattDescrip
public String getUUID() { return uuid; }
@Override
- public native BluetoothType getBluetoothType();
- @Override
- public native BluetoothGattDescriptor clone();
+ public BluetoothType getBluetoothType() { return class_type(); }
static BluetoothType class_type() { return BluetoothType.GATT_DESCRIPTOR; }
+ @Override
+ public final GattDescriptor clone()
+ { throw new UnsupportedOperationException(); } // FIXME
+
/* D-Bus method calls: */
@Override
@@ -77,10 +79,11 @@ public class HCIGattDescriptor extends HCIObject implements BluetoothGattDescrip
/* D-Bus property accessors: */
@Override
- public native HCIGattCharacteristic getCharacteristic();
+ public native GattCharacteristic getCharacteristic();
@Override
public native byte[] getValue();
- private native void delete();
+ @Override
+ protected native void deleteImpl();
}
diff --git a/java/tinyb/hci/HCIGattService.java b/java/direct_bt/tinyb/GattService.java
index 584f68b3..8377c806 100644
--- a/java/tinyb/hci/HCIGattService.java
+++ b/java/direct_bt/tinyb/GattService.java
@@ -23,7 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-package tinyb.hci;
+package direct_bt.tinyb;
import java.util.List;
@@ -32,23 +32,23 @@ import org.tinyb.BluetoothGattService;
import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothType;
-public class HCIGattService extends HCIObject implements BluetoothGattService
+public class GattService extends DBTObject implements BluetoothGattService
{
private final String uuid;
- /* pp */ HCIGattService(final String uuid)
+ /* pp */ GattService(final long nativeInstance, final String uuid)
{
- super(uuid.hashCode());
+ super(nativeInstance, uuid.hashCode());
this.uuid = uuid;
}
@Override
public boolean equals(final Object obj)
{
- if (obj == null || !(obj instanceof HCIGattService)) {
+ if (obj == null || !(obj instanceof GattService)) {
return false;
}
- final HCIGattService other = (HCIGattService)obj;
+ final GattService other = (GattService)obj;
return uuid.equals(other.uuid);
}
@@ -56,17 +56,18 @@ public class HCIGattService extends HCIObject implements BluetoothGattService
public String getUUID() { return uuid; }
@Override
- public native BluetoothType getBluetoothType();
-
- @Override
- public native BluetoothGattService clone();
+ public BluetoothType getBluetoothType() { return class_type(); }
static BluetoothType class_type() { return BluetoothType.GATT_SERVICE; }
@Override
+ public final GattService clone()
+ { throw new UnsupportedOperationException(); } // FIXME
+
+ @Override
public BluetoothGattCharacteristic find(final String UUID, final long timeoutMS) {
- final BluetoothManager manager = HCIManager.getBluetoothManager();
- return (HCIGattCharacteristic) manager.find(BluetoothType.GATT_CHARACTERISTIC,
+ final BluetoothManager manager = Manager.getBluetoothManager();
+ return (GattCharacteristic) manager.find(BluetoothType.GATT_CHARACTERISTIC,
null, UUID, this, timeoutMS);
}
@@ -78,7 +79,7 @@ public class HCIGattService extends HCIObject implements BluetoothGattService
/* D-Bus property accessors: */
@Override
- public native HCIDevice getDevice();
+ public native Device getDevice();
@Override
public native boolean getPrimary();
@@ -86,5 +87,6 @@ public class HCIGattService extends HCIObject implements BluetoothGattService
@Override
public native List<BluetoothGattCharacteristic> getCharacteristics();
- private native void delete();
+ @Override
+ protected native void deleteImpl();
}
diff --git a/java/tinyb/hci/HCIManager.java b/java/direct_bt/tinyb/Manager.java
index 7afba39c..99ea2cce 100644
--- a/java/tinyb/hci/HCIManager.java
+++ b/java/direct_bt/tinyb/Manager.java
@@ -23,7 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-package tinyb.hci;
+package direct_bt.tinyb;
import java.util.ArrayList;
import java.util.List;
@@ -36,30 +36,31 @@ import org.tinyb.BluetoothObject;
import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothType;
-public class HCIManager implements BluetoothManager
+public class Manager implements BluetoothManager
{
- private static HCIManager inst;
+ private long nativeInstance;
+ private static Manager inst;
private final List<BluetoothAdapter> adapters = new ArrayList<BluetoothAdapter>();
- public native BluetoothType getBluetoothType();
+ public BluetoothType getBluetoothType() { return BluetoothType.NONE; }
- private HCIObject find(final int type, final String name, final String identifier, final BluetoothObject parent, final long milliseconds)
+ private DBTObject find(final int type, final String name, final String identifier, final BluetoothObject parent, final long milliseconds)
{ throw new UnsupportedOperationException(); } // FIXME
@Override
- public HCIObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent, final long timeoutMS) {
+ public DBTObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent, final long timeoutMS) {
return find(type.ordinal(), name, identifier, parent, timeoutMS);
}
@Override
- public HCIObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent) {
+ public DBTObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent) {
return find(type, name, identifier, parent, 0);
}
@SuppressWarnings("unchecked")
@Override
public <T extends BluetoothObject> T find(final String name, final String identifier, final BluetoothObject parent, final long timeoutMS) {
- return (T) find(HCIObject.class_type().ordinal(), name, identifier, parent, timeoutMS);
+ return (T) find(DBTObject.class_type().ordinal(), name, identifier, parent, timeoutMS);
}
@SuppressWarnings("unchecked")
@@ -108,12 +109,22 @@ public class HCIManager implements BluetoothManager
@Override
public boolean getDiscovering() throws BluetoothException { return getDefaultAdapter().getDiscovering(); }
- private native HCIAdapter init() throws BluetoothException;
- private native void delete();
+ /**
+ * Returns an opened default adapter instance!
+ * @throws BluetoothException in case adapter is invalid or could not have been opened.
+ */
+ private native Adapter getDefaultAdapterImpl() throws BluetoothException;
- private HCIManager()
+ private native void initImpl() throws BluetoothException;
+ private native void deleteImpl();
+ private Manager()
{
- adapters.add(init());
+ initImpl();
+ try {
+ adapters.add(getDefaultAdapterImpl());
+ } catch (final BluetoothException be) {
+ be.printStackTrace();
+ }
}
/** Returns an instance of BluetoothManager, to be used instead of constructor.
@@ -123,15 +134,20 @@ public class HCIManager implements BluetoothManager
{
if (inst == null)
{
- inst = new HCIManager();
+ inst = new Manager();
}
return inst;
}
@Override
- protected void finalize()
- {
+ protected void finalize() {
+ shutdown();
+ }
+
+ @Override
+ public void shutdown() {
adapters.clear();
- delete();
+ deleteImpl();
}
+
}
diff --git a/java/direct_bt/tinyb/NativeDownlink.java b/java/direct_bt/tinyb/NativeDownlink.java
new file mode 100644
index 00000000..72e4e137
--- /dev/null
+++ b/java/direct_bt/tinyb/NativeDownlink.java
@@ -0,0 +1,87 @@
+/**
+ * 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.
+ */
+
+package direct_bt.tinyb;
+
+import org.tinyb.BluetoothFactory;
+
+public abstract class NativeDownlink
+{
+ protected long nativeInstance;
+ private boolean isValid;
+
+ static {
+ try {
+ System.loadLibrary(BluetoothFactory.JavaNativeLibBasename);
+ } catch (final Throwable e) {
+ System.err.println("Failed to load native library "+BluetoothFactory.JavaNativeLibBasename);
+ e.printStackTrace();
+ throw e; // fwd exception - end here
+ }
+ }
+
+ protected NativeDownlink(final long nativeInstance)
+ {
+ this.nativeInstance = nativeInstance;
+ isValid = true;
+ initNativeJavaObject(nativeInstance);
+ }
+
+ @Override
+ protected void finalize()
+ {
+ delete();
+ }
+
+ /**
+ * Deletes the native instance in the following order
+ * <ol>
+ * <li>Removes this java reference from the native instance</li>
+ * <li>Deletes the native instance via {@link #deleteImpl()}</li>
+ * <li>Sets the nativeInstance := 0</li>
+ * </ol>
+ */
+ public synchronized void delete() {
+ if (!isValid) {
+ return;
+ }
+ isValid = false;
+ clearNativeJavaObject(nativeInstance);
+ deleteImpl();
+ nativeInstance = 0;
+ }
+
+ /**
+ * Deletes the native instance.
+ * <p>
+ * Called via {@link #delete()} and at this point this java reference
+ * has been removed from the native instance.
+ * </p>
+ */
+ protected abstract void deleteImpl();
+
+ private native void initNativeJavaObject(final long nativeInstance);
+ private native void clearNativeJavaObject(final long nativeInstance);
+}
diff --git a/java/jni/BluetoothUtils.cxx b/java/jni/BluetoothUtils.cxx
new file mode 100644
index 00000000..83e71dd0
--- /dev/null
+++ b/java/jni/BluetoothUtils.cxx
@@ -0,0 +1,53 @@
+/*
+ * 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 "org_tinyb_BluetoothUtils.h"
+
+#include <cstdint>
+#include <cinttypes>
+
+#include <time.h>
+
+static const int64_t NanoPerMilli = 1000000L;
+static const int64_t MilliPerOne = 1000L;
+
+/**
+ * See <http://man7.org/linux/man-pages/man2/clock_gettime.2.html>
+ * <p>
+ * Regarding avoiding kernel via VDSO,
+ * see <http://man7.org/linux/man-pages/man7/vdso.7.html>,
+ * clock_gettime seems to be well supported at least on kernel >= 4.4.
+ * Only bfin and sh are missing, while ia64 seems to be complicated.
+ */
+jlong Java_org_tinyb_BluetoothUtils_getCurrentMilliseconds(JNIEnv *env, jclass clazz) {
+ (void)env;
+ (void)clazz;
+
+ struct timespec t;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ int64_t res = t.tv_sec * MilliPerOne + t.tv_nsec / NanoPerMilli;
+ return (jlong)res;
+}
+
diff --git a/java/jni/CMakeLists.txt b/java/jni/CMakeLists.txt
deleted file mode 100644
index cd715a5a..00000000
--- a/java/jni/CMakeLists.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-find_package(JNI REQUIRED)
-
-if (JNI_FOUND)
- message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}")
- message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}")
-endif (JNI_FOUND)
-
-set (tinyb_LIB_INCLUDE_DIRS
- ${PROJECT_SOURCE_DIR}/api
- ${PROJECT_SOURCE_DIR}/api/tinyb
- ${PROJECT_SOURCE_DIR}/api/direct_bt
- ${PROJECT_SOURCE_DIR}/include
-)
-
-include_directories(
- ${JNI_INCLUDE_DIRS}
- ${tinyb_LIB_INCLUDE_DIRS}
- ${JNI_HEADER_PATH}
-)
-
-file(GLOB JNI_SOURCES "*.cxx")
-
-set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed")
-
-add_library (javatinyb SHARED ${JNI_SOURCES})
-target_link_libraries(javatinyb ${JNI_LIBRARIES} tinyb)
-
-set_target_properties(
- javatinyb
- PROPERTIES
- SOVERSION ${tinyb_VERSION_MAJOR}
- VERSION ${tinyb_VERSION_STRING}
- CXX_STANDARD 11
- COMPILE_FLAGS "-Wall -Wextra"
-)
-
-install(TARGETS javatinyb LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
-
diff --git a/java/jni/HCIManager.cxx b/java/jni/HCIManager.cxx
deleted file mode 100644
index 57865644..00000000
--- a/java/jni/HCIManager.cxx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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/HCITypes.hpp"
-
-#include "JNIMem.hpp"
-#include "helper_base.hpp"
-
diff --git a/java/jni/HCIObject.cxx b/java/jni/HCIObject.cxx
deleted file mode 100644
index 1f420eea..00000000
--- a/java/jni/HCIObject.cxx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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/HCITypes.hpp"
-
-#include "tinyb_hci_HCIObject.h"
-
-#include "JNIMem.hpp"
-#include "helper_base.hpp"
-
-using namespace direct_bt;
-
diff --git a/java/jni/JNIMem.cxx b/java/jni/JNIMem.cxx
index 9861995c..ecea39aa 100644
--- a/java/jni/JNIMem.cxx
+++ b/java/jni/JNIMem.cxx
@@ -2,6 +2,10 @@
* Author: Petre Eftime <[email protected]>
* Copyright (c) 2016 Intel Corporation.
*
+ * 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
@@ -60,14 +64,14 @@ void JNIEnvContainer::attach() {
if( JNI_EDETACHED == envRes ) {
envRes = vm->AttachCurrentThreadAsDaemon((void**) &newEnv, NULL);
if( JNI_OK != envRes ) {
- throw std::runtime_error("Attach to VM failed");
+ throw direct_bt::RuntimeException("Attach to VM failed", E_FILE_LINE);
}
env = newEnv;
} else if( JNI_OK != envRes ) {
- throw std::runtime_error("GetEnv of VM failed");
+ throw direct_bt::RuntimeException("GetEnv of VM failed", E_FILE_LINE);
}
if (env==NULL) {
- throw std::runtime_error("GetEnv of VM is NULL");
+ throw direct_bt::RuntimeException("GetEnv of VM is NULL", E_FILE_LINE);
}
needsDetach = NULL != newEnv;
}
@@ -84,13 +88,24 @@ void JNIEnvContainer::detach() {
}
JNIGlobalRef::JNIGlobalRef(jobject object) {
+ if( nullptr == object ) {
+ throw direct_bt::RuntimeException("JNIGlobalRef ctor null jobject", E_FILE_LINE);
+ }
this->object = jni_env->NewGlobalRef(object);
}
JNIGlobalRef::~JNIGlobalRef() {
- jni_env->DeleteGlobalRef(object);
-}
-
-jobject JNIGlobalRef::operator*() {
- return object;
+ try {
+ JNIEnv * env = *jni_env;
+ if( nullptr == env ) {
+ throw direct_bt::RuntimeException("JNIGlobalRef dtor null JNIEnv", E_FILE_LINE);
+ }
+ if( nullptr == object ) {
+ throw direct_bt::RuntimeException("JNIGlobalRef dtor null jobject", E_FILE_LINE);
+ } else {
+ env->DeleteGlobalRef(object);
+ }
+ } catch (std::exception &e) {
+ fprintf(stderr, "JNIGlobalRef dtor: Caught %s\n", e.what());
+ }
}
diff --git a/java/jni/JNIMem.hpp b/java/jni/JNIMem.hpp
index 389a9157..a133bd9a 100644
--- a/java/jni/JNIMem.hpp
+++ b/java/jni/JNIMem.hpp
@@ -2,6 +2,10 @@
* Author: Petre Eftime <[email protected]>
* Copyright (c) 2016 Intel Corporation.
*
+ * 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
@@ -22,10 +26,14 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#pragma once
+#ifndef JNIMEM__HPP_
+#define JNIMEM__HPP_
+
#include <jni.h>
#include <stdexcept>
+#include "BasicTypes.hpp"
+
extern JavaVM* vm;
@@ -67,12 +75,26 @@ private:
jobject object;
public:
+ static inline void check(jobject object, const char* file, int line) {
+ if( nullptr == object ) {
+ throw direct_bt::RuntimeException("JNIGlobalRef::check: Null jobject", file, line);
+ }
+ }
+
/* Creates a GlobalRef from an object passed to it */
JNIGlobalRef(jobject object);
+
/* Deletes the stored GlobalRef */
~JNIGlobalRef();
- /* Provides access to the stored GlobalRef */
- jobject operator*();
+ /* Provides access to the stored GlobalRef as an jobject. */
+ jobject operator*() { return object; }
+
+ /* Provides access to the stored GlobalRef as an jobject. */
+ jobject getObject() const { return object; }
+ /* Provides access to the stored GlobalRef as a jclass. */
+ jclass getClass() const { return (jclass)object; }
};
+#endif /* JNIMEM__HPP_ */
+
diff --git a/java/jni/direct_bt/CMakeLists.txt b/java/jni/direct_bt/CMakeLists.txt
new file mode 100644
index 00000000..7622569f
--- /dev/null
+++ b/java/jni/direct_bt/CMakeLists.txt
@@ -0,0 +1,53 @@
+find_package(JNI REQUIRED)
+
+if (JNI_FOUND)
+ message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}")
+ message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}")
+endif (JNI_FOUND)
+
+set (direct_bt_LIB_INCLUDE_DIRS
+ ${PROJECT_SOURCE_DIR}/api
+ ${PROJECT_SOURCE_DIR}/api/direct_bt
+ ${PROJECT_SOURCE_DIR}/include
+ ${PROJECT_SOURCE_DIR}/java/jni
+)
+
+include_directories(
+ ${JNI_INCLUDE_DIRS}
+ ${direct_bt_LIB_INCLUDE_DIRS}
+ ${JNI_HEADER_PATH}
+)
+
+set (direct_bt_JNI_SRCS
+ ${PROJECT_SOURCE_DIR}/java/jni/JNIMem.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/helper_base.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/BluetoothFactory.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/BluetoothUtils.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/helper_dbt.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTNativeDownlink.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTAdapter.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTDevice.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTEvent.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTGattCharacteristic.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTGattDescriptor.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTGattService.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTManager.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTObject.cxx
+)
+
+set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed")
+
+add_library (javadirect_bt SHARED ${direct_bt_JNI_SRCS})
+target_link_libraries(javadirect_bt ${JNI_LIBRARIES} direct_bt)
+
+set_target_properties(
+ javadirect_bt
+ PROPERTIES
+ SOVERSION ${tinyb_VERSION_MAJOR}
+ VERSION ${tinyb_VERSION_STRING}
+ CXX_STANDARD 11
+ COMPILE_FLAGS "-Wall -Wextra"
+)
+
+install(TARGETS javadirect_bt LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx
new file mode 100644
index 00000000..3f634dc2
--- /dev/null
+++ b/java/jni/direct_bt/DBTAdapter.cxx
@@ -0,0 +1,259 @@
+/*
+ * 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_tinyb_Adapter.h"
+
+// #define VERBOSE_ON 1
+#include <dbt_debug.hpp>
+
+#include "JNIMem.hpp"
+#include "helper_base.hpp"
+#include "helper_dbt.hpp"
+
+#include "direct_bt/HCITypes.hpp"
+
+using namespace direct_bt;
+
+static const std::string _deviceClazzCtorArgs("(JLdirect_bt/tinyb/Adapter;Ljava/lang/String;Ljava/lang/String;J)V");
+static const std::string _deviceDiscoveryMethodArgs("(Lorg/tinyb/BluetoothAdapter;Lorg/tinyb/BluetoothDevice;)V");
+
+class DeviceDiscoveryCallbackListener : public HCIDeviceDiscoveryListener {
+ public:
+ /**
+ package org.tinyb;
+
+ public interface BluetoothDeviceDiscoveryListener {
+ public void deviceAdded(final BluetoothAdapter adapter, final BluetoothDevice device);
+ public void deviceUpdated(final BluetoothAdapter adapter, final BluetoothDevice device);
+ public void deviceRemoved(final BluetoothAdapter adapter, final BluetoothDevice device);
+ };
+ */
+ std::shared_ptr<JavaAnonObj> adapterObjRef;
+ std::unique_ptr<JNIGlobalRef> deviceClazzRef;
+ jmethodID deviceClazzCtor;
+ jfieldID deviceClazzTSUpdateField;
+ std::unique_ptr<JNIGlobalRef> listenerObjRef;
+ std::unique_ptr<JNIGlobalRef> listenerClazzRef;
+ jmethodID mDeviceAdded = nullptr;
+ jmethodID mDeviceUpdated = nullptr;
+ jmethodID mDeviceRemoved = nullptr;
+
+ DeviceDiscoveryCallbackListener(JNIEnv *env, HCIAdapter *adapter, jobject deviceDiscoveryListener) {
+ adapterObjRef = adapter->getJavaObject();
+ JavaGlobalObj::check(adapterObjRef, E_FILE_LINE);
+ {
+ jclass deviceClazz = search_class(*jni_env, HCIDevice::java_class().c_str());
+ if( nullptr == deviceClazz ) {
+ throw InternalError("HCIDevice::java_class not found: "+HCIDevice::java_class(), E_FILE_LINE);
+ }
+ deviceClazzRef = std::unique_ptr<JNIGlobalRef>(new JNIGlobalRef(deviceClazz));
+ env->DeleteLocalRef(deviceClazz);
+ }
+ deviceClazzCtor = search_method(*jni_env, deviceClazzRef->getClass(), "<init>", _deviceClazzCtorArgs.c_str(), false);
+ if( nullptr == deviceClazzCtor ) {
+ throw InternalError("HCIDevice::java_class ctor not found: "+HCIDevice::java_class()+".<init>"+_deviceClazzCtorArgs, E_FILE_LINE);
+ }
+ deviceClazzTSUpdateField = jni_env->GetFieldID(deviceClazzRef->getClass(), "ts_update", "J");
+ if( nullptr == deviceClazzTSUpdateField ) {
+ throw InternalError("HCIDevice::java_class field not found: "+HCIDevice::java_class()+".ts_update", E_FILE_LINE);
+ }
+
+ listenerObjRef = std::unique_ptr<JNIGlobalRef>(new JNIGlobalRef(deviceDiscoveryListener));
+ {
+ jclass listenerClazz = search_class(env, listenerObjRef->getObject());
+ if( nullptr == listenerClazz ) {
+ throw InternalError("BluetoothDeviceDiscoveryListener not found", E_FILE_LINE);
+ }
+ listenerClazzRef = std::unique_ptr<JNIGlobalRef>(new JNIGlobalRef(listenerClazz));
+ env->DeleteLocalRef(listenerClazz);
+ }
+ mDeviceAdded = search_method(env, listenerClazzRef->getClass(), "deviceAdded", _deviceDiscoveryMethodArgs.c_str(), false);
+ mDeviceUpdated = search_method(env, listenerClazzRef->getClass(), "deviceUpdated", _deviceDiscoveryMethodArgs.c_str(), false);
+ mDeviceRemoved = search_method(env, listenerClazzRef->getClass(), "deviceRemoved", _deviceDiscoveryMethodArgs.c_str(), false);
+ if( nullptr == mDeviceAdded ) {
+ throw InternalError("BluetoothDeviceDiscoveryListener has no deviceAdded"+_deviceDiscoveryMethodArgs+" method, for "+adapter->toString(), E_FILE_LINE);
+ }
+ if( nullptr == mDeviceUpdated ) {
+ throw InternalError("BluetoothDeviceDiscoveryListener has no deviceUpdated"+_deviceDiscoveryMethodArgs+" method, for "+adapter->toString(), E_FILE_LINE);
+ }
+ if( nullptr == mDeviceRemoved ) {
+ throw InternalError("BluetoothDeviceDiscoveryListener has no deviceRemoved"+_deviceDiscoveryMethodArgs+" method, for "+adapter->toString(), E_FILE_LINE);
+ }
+ exception_check_raise_and_throw(env, E_FILE_LINE);
+ }
+
+ void deviceAdded(HCIAdapter const &a, std::shared_ptr<HCIDevice> device) override {
+ try {
+ #ifdef VERBOSE_ON
+ fprintf(stderr, "****** Native Adapter Device ADDED__: %s\n", device->toString().c_str());
+ fprintf(stderr, "Status HCIAdapter:\n");
+ fprintf(stderr, "%s\n", a.toString().c_str());
+ #endif
+
+ // Device(final long nativeInstance, final Adapter adptr, final String address, final String name)
+ const jstring addr = from_string_to_jstring(*jni_env, device->getAddressString());
+ const jstring name = from_string_to_jstring(*jni_env, device->getName());
+ jobject jDevice = jni_env->NewObject(deviceClazzRef->getClass(), deviceClazzCtor,
+ (jlong)device.get(), adapterObjRef, addr, name, (jlong)device->ts_creation);
+ exception_check_raise_and_throw(*jni_env, E_FILE_LINE);
+ JNIGlobalRef::check(jDevice, E_FILE_LINE);
+ std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
+ JavaGlobalObj::check(jDeviceRef, E_FILE_LINE);
+
+ jni_env->CallVoidMethod(listenerObjRef->getObject(), mDeviceAdded, JavaGlobalObj::GetObject(adapterObjRef), JavaGlobalObj::GetObject(jDeviceRef));
+ exception_check_raise_and_throw(*jni_env, E_FILE_LINE);
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(*jni_env, e)
+ }
+ void deviceUpdated(HCIAdapter const &a, std::shared_ptr<HCIDevice> device) override {
+ try {
+ #ifdef VERBOSE_ON
+ fprintf(stderr, "****** Native Adapter Device UPDATED: %s\n", device->toString().c_str());
+ fprintf(stderr, "Status HCIAdapter:\n");
+ fprintf(stderr, "%s\n", a.toString().c_str());
+ #endif
+ std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
+ JavaGlobalObj::check(jDeviceRef, E_FILE_LINE);
+ jni_env->SetLongField(JavaGlobalObj::GetObject(jDeviceRef), deviceClazzTSUpdateField, (jlong)device->getUpdateTimestamp());
+ jni_env->CallVoidMethod(listenerObjRef->getObject(), mDeviceUpdated, JavaGlobalObj::GetObject(adapterObjRef), JavaGlobalObj::GetObject(jDeviceRef));
+ exception_check_raise_and_throw(*jni_env, E_FILE_LINE);
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(*jni_env, e)
+ }
+ void deviceRemoved(HCIAdapter const &a, std::shared_ptr<HCIDevice> device) override {
+ try {
+ #ifdef VERBOSE_ON
+ fprintf(stderr, "****** DBTAdapter Device REMOVED: %s\n", device->toString().c_str());
+ fprintf(stderr, "Status HCIAdapter:\n");
+ fprintf(stderr, "%s\n", a.toString().c_str());
+ #endif
+ std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject();
+ JavaGlobalObj::check(jDeviceRef, E_FILE_LINE);
+ jni_env->SetLongField(JavaGlobalObj::GetObject(jDeviceRef), deviceClazzTSUpdateField, (jlong)device->getUpdateTimestamp());
+ jni_env->CallVoidMethod(listenerObjRef->getObject(), mDeviceRemoved, JavaGlobalObj::GetObject(adapterObjRef), JavaGlobalObj::GetObject(jDeviceRef));
+ exception_check_raise_and_throw(*jni_env, E_FILE_LINE);
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(*jni_env, e)
+ }
+};
+
+void Java_direct_1bt_tinyb_Adapter_initImpl(JNIEnv *env, jobject obj, jobject deviceDiscoveryListener)
+{
+ // org.tinyb.BluetoothDeviceDiscoveryListener
+ try {
+ HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj);
+ JavaGlobalObj::check(adapter->getJavaObject(), E_FILE_LINE);
+
+ // set our callback discovery listener.
+ DeviceDiscoveryCallbackListener *l = new DeviceDiscoveryCallbackListener(env, adapter, deviceDiscoveryListener);
+ adapter->setDeviceDiscoveryListener(std::shared_ptr<HCIDeviceDiscoveryListener>(l));
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+}
+
+void Java_direct_1bt_tinyb_Adapter_deleteImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj);
+ DBG_PRINT("Java_direct_1bt_tinyb_Adapter_deleteImpl %s", adapter->toString().c_str());
+ delete adapter;
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+}
+
+jboolean Java_direct_1bt_tinyb_Adapter_startDiscoveryImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj);
+ std::shared_ptr<direct_bt::HCISession> session = adapter->getOpenSession();
+ if( nullptr == session ) {
+ throw BluetoothException("No adapter session: "+adapter->toString(), E_FILE_LINE);
+ }
+ if( !session->isOpen() ) {
+ throw BluetoothException("No open adapter session: "+adapter->toString(), E_FILE_LINE);
+ }
+ return adapter->startDiscovery(*session);
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+ return JNI_FALSE;
+}
+
+jboolean Java_direct_1bt_tinyb_Adapter_stopDiscoveryImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj);
+ std::shared_ptr<direct_bt::HCISession> session = adapter->getOpenSession();
+ if( nullptr == session ) {
+ throw BluetoothException("No adapter session: "+adapter->toString(), E_FILE_LINE);
+ }
+ if( !session->isOpen() ) {
+ throw BluetoothException("No open adapter session: "+adapter->toString(), E_FILE_LINE);
+ }
+ adapter->setDeviceDiscoveryListener(nullptr);
+ adapter->stopDiscovery(*session);
+ return JNI_TRUE;
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+ return JNI_FALSE;
+}
+
+jint Java_direct_1bt_tinyb_Adapter_discoverAnyDeviceImpl(JNIEnv *env, jobject obj, jint timeoutMS)
+{
+ try {
+ HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj);
+ std::shared_ptr<direct_bt::HCISession> session = adapter->getOpenSession();
+ if( nullptr == session ) {
+ throw BluetoothException("No adapter session: "+adapter->toString(), E_FILE_LINE);
+ }
+ if( !session->isOpen() ) {
+ throw BluetoothException("No open adapter session: "+adapter->toString(), E_FILE_LINE);
+ }
+ return adapter->discoverDevices(*session, -1, EUI48_ANY_DEVICE, timeoutMS, static_cast<uint32_t>(EInfoReport::Element::NAME));
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+ return 0;
+}
+
+jobject Java_direct_1bt_tinyb_Adapter_getDiscoveredDevicesImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj);
+ /**
+ std::function<jobject(JNIEnv*, jclass, jmethodID, HCIDevice*)> ctor_device = [&](JNIEnv *env, jclass clazz, jmethodID clazz_ctor, HCIDevice *elem) {
+ // Device(final long nativeInstance, final Adapter adptr, final String address, final String name)
+ jstring addr = from_string_to_jstring(env, elem->getAddressString());
+ jstring name = from_string_to_jstring(env, elem->getName());
+ jobject object = env->NewObject(clazz, clazz_ctor, (jlong)elem, obj, addr, name);
+ return object;
+ };
+ return convert_vector_to_jobject<HCIDevice>(env, array, "(JLdirect_bt/tinyb/Adapter;Ljava/lang/String;Ljava/lang/String;)V", ctor_device);
+ */
+ std::vector<std::shared_ptr<HCIDevice>> array = adapter->getDiscoveredDevices();
+ return convert_vector_to_jobject(env, array);
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+ return nullptr;
+}
+
+jint Java_direct_1bt_tinyb_Adapter_removeDevicesImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj);
+ return adapter->removeDiscoveredDevices();
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+ return 0;
+}
+
diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx
new file mode 100644
index 00000000..b2887b55
--- /dev/null
+++ b/java/jni/direct_bt/DBTDevice.cxx
@@ -0,0 +1,78 @@
+/*
+ * 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_tinyb_Device.h"
+
+#include "JNIMem.hpp"
+#include "helper_base.hpp"
+#include "helper_dbt.hpp"
+
+#include "direct_bt/HCITypes.hpp"
+
+using namespace direct_bt;
+
+void Java_direct_1bt_tinyb_Device_initImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ HCIDevice *device = getInstance<HCIDevice>(env, obj);
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+}
+
+void Java_direct_1bt_tinyb_Device_deleteImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ HCIDevice *device = getInstance<HCIDevice>(env, obj);
+ delete device;
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+}
+
+jshort Java_direct_1bt_tinyb_Device_getRSSI(JNIEnv *env, jobject obj)
+{
+ try {
+ HCIDevice *device = getInstance<HCIDevice>(env, obj);
+ return device->getRSSI();
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+ return 0;
+}
+
+jshort Java_direct_1bt_tinyb_Device_getTxPower(JNIEnv *env, jobject obj)
+{
+ try {
+ HCIDevice *device = getInstance<HCIDevice>(env, obj);
+ return device->getTxPower();
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+ return 0;
+}
+
+jboolean Java_direct_1bt_tinyb_Device_getConnected(JNIEnv *env, jobject obj)
+{
+ try {
+ HCIDevice *device = getInstance<HCIDevice>(env, obj);
+ (void) device;
+ return JNI_TRUE; // FIXME
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+ return JNI_FALSE;
+}
diff --git a/java/jni/HCIEvent.cxx b/java/jni/direct_bt/DBTEvent.cxx
index b1bc89c5..e9203d48 100644
--- a/java/jni/HCIEvent.cxx
+++ b/java/jni/direct_bt/DBTEvent.cxx
@@ -23,9 +23,9 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "tinyb_hci_HCIEvent.h"
+#include "direct_bt_tinyb_DBTEvent.h"
-jobject Java_tinyb_hci_HCIEvent_getType(JNIEnv *env, jobject obj)
+jobject Java_direct_1bt_tinyb_DBTEvent_getType(JNIEnv *env, jobject obj)
{
(void)env;
(void)obj;
@@ -33,7 +33,7 @@ jobject Java_tinyb_hci_HCIEvent_getType(JNIEnv *env, jobject obj)
return NULL;
}
-jstring Java_tinyb_hci_HCIEvent_getName(JNIEnv *env, jobject obj)
+jstring Java_direct_1bt_tinyb_DBTEvent_getName(JNIEnv *env, jobject obj)
{
(void)env;
(void)obj;
@@ -41,7 +41,7 @@ jstring Java_tinyb_hci_HCIEvent_getName(JNIEnv *env, jobject obj)
return NULL;
}
-jstring Java_tinyb_hci_HCIEvent_getIdentifier(JNIEnv *env, jobject obj)
+jstring Java_direct_1bt_tinyb_DBTEvent_getIdentifier(JNIEnv *env, jobject obj)
{
(void)env;
(void)obj;
@@ -49,7 +49,7 @@ jstring Java_tinyb_hci_HCIEvent_getIdentifier(JNIEnv *env, jobject obj)
return NULL;
}
-jboolean Java_tinyb_hci_HCIEvent_executeCallback(JNIEnv *env, jobject obj)
+jboolean Java_direct_1bt_tinyb_DBTEvent_executeCallback(JNIEnv *env, jobject obj)
{
(void)env;
(void)obj;
@@ -57,7 +57,7 @@ jboolean Java_tinyb_hci_HCIEvent_executeCallback(JNIEnv *env, jobject obj)
return JNI_FALSE;
}
-jboolean Java_tinyb_hci_HCIEvent_hasCallback(JNIEnv *env, jobject obj)
+jboolean Java_direct_1bt_tinyb_DBTEvent_hasCallback(JNIEnv *env, jobject obj)
{
(void)env;
(void)obj;
@@ -65,9 +65,9 @@ jboolean Java_tinyb_hci_HCIEvent_hasCallback(JNIEnv *env, jobject obj)
return JNI_FALSE;
}
-void Java_tinyb_hci_HCIEvent_init(JNIEnv *env, jobject obj, jobject type, jstring name,
- jstring identifier, jobject parent, jobject callback,
- jobject arg_data)
+void Java_direct_1bt_tinyb_DBTEvent_init(JNIEnv *env, jobject obj, jobject type, jstring name,
+ jstring identifier, jobject parent, jobject callback,
+ jobject arg_data)
{
(void)env;
(void)obj;
@@ -79,7 +79,7 @@ void Java_tinyb_hci_HCIEvent_init(JNIEnv *env, jobject obj, jobject type, jstrin
(void)arg_data;
}
-void Java_tinyb_hci_HCIEvent_delete(JNIEnv *env, jobject obj)
+void Java_direct_1bt_tinyb_DBTEvent_delete(JNIEnv *env, jobject obj)
{
(void)env;
(void)obj;
diff --git a/java/jni/HCIGattCharacteristic.cxx b/java/jni/direct_bt/DBTGattCharacteristic.cxx
index 0a0c4c07..cae33960 100644
--- a/java/jni/HCIGattCharacteristic.cxx
+++ b/java/jni/direct_bt/DBTGattCharacteristic.cxx
@@ -23,12 +23,12 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "direct_bt/HCITypes.hpp"
-
-#include "tinyb_hci_HCIGattCharacteristic.h"
+#include "direct_bt_tinyb_GattCharacteristic.h"
#include "JNIMem.hpp"
#include "helper_base.hpp"
+#include "direct_bt/HCITypes.hpp"
+
using namespace direct_bt;
diff --git a/java/jni/HCIAdapter.cxx b/java/jni/direct_bt/DBTGattDescriptor.cxx
index afb420fc..59410d92 100644
--- a/java/jni/HCIAdapter.cxx
+++ b/java/jni/direct_bt/DBTGattDescriptor.cxx
@@ -23,12 +23,12 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "direct_bt/HCITypes.hpp"
-
-#include "tinyb_hci_HCIAdapter.h"
+#include "direct_bt_tinyb_GattDescriptor.h"
#include "JNIMem.hpp"
#include "helper_base.hpp"
+#include "direct_bt/HCITypes.hpp"
+
using namespace direct_bt;
diff --git a/java/jni/HCIGattDescriptor.cxx b/java/jni/direct_bt/DBTGattService.cxx
index cefc6b4d..6e0fe141 100644
--- a/java/jni/HCIGattDescriptor.cxx
+++ b/java/jni/direct_bt/DBTGattService.cxx
@@ -23,12 +23,12 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "direct_bt/HCITypes.hpp"
-
-#include "tinyb_hci_HCIGattDescriptor.h"
+#include "direct_bt_tinyb_GattService.h"
#include "JNIMem.hpp"
#include "helper_base.hpp"
+#include "direct_bt/HCITypes.hpp"
+
using namespace direct_bt;
diff --git a/java/jni/direct_bt/DBTManager.cxx b/java/jni/direct_bt/DBTManager.cxx
new file mode 100644
index 00000000..0c01272d
--- /dev/null
+++ b/java/jni/direct_bt/DBTManager.cxx
@@ -0,0 +1,106 @@
+/*
+ * 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_tinyb_Manager.h"
+
+// #define VERBOSE_ON 1
+#include <dbt_debug.hpp>
+
+#include "JNIMem.hpp"
+#include "helper_base.hpp"
+#include "helper_dbt.hpp"
+
+#include "direct_bt/HCITypes.hpp"
+
+using namespace direct_bt;
+
+void Java_direct_1bt_tinyb_Manager_initImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ MgmtHandler *manager = &MgmtHandler::get(); // special: static singleton
+ setInstance<MgmtHandler>(env, obj, manager);
+ manager->setJavaObject( std::shared_ptr<JavaAnonObj>( new JavaGlobalObj(obj) ) );
+ JavaGlobalObj::check(manager->getJavaObject(), E_FILE_LINE);
+ DBG_PRINT("Java_direct_1bt_tinyb_Manager_init: Manager %s", manager->toString().c_str());
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+}
+
+void Java_direct_1bt_tinyb_Manager_deleteImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ MgmtHandler *manager = getInstance<MgmtHandler>(env, obj); // special: static singleton
+ manager->setJavaObject(nullptr);
+ // delete manager;
+ (void) manager;
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+}
+
+static const std::string _adapterClazzCtorArgs("(JLjava/lang/String;Ljava/lang/String;)V");
+
+jobject Java_direct_1bt_tinyb_Manager_getDefaultAdapterImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ MgmtHandler *manager = getInstance<MgmtHandler>(env, obj);
+ DBG_PRINT("Java_direct_1bt_tinyb_Manager_getDefaultAdapterImpl: Manager %s", manager->toString().c_str());
+ int defAdapterIdx = manager->getDefaultAdapterIdx();
+ HCIAdapter * adapter = new HCIAdapter(defAdapterIdx);
+ if( !adapter->isValid() ) {
+ delete adapter;
+ throw BluetoothException("Invalid default adapter "+std::to_string(defAdapterIdx), E_FILE_LINE);
+ }
+ if( !adapter->hasDevId() ) {
+ delete adapter;
+ throw BluetoothException("Invalid default adapter dev-id "+std::to_string(defAdapterIdx), E_FILE_LINE);
+ }
+ std::shared_ptr<direct_bt::HCISession> session = adapter->open();
+ if( nullptr == session ) {
+ delete adapter;
+ throw BluetoothException("Couldn't open default adapter "+std::to_string(defAdapterIdx), E_FILE_LINE);
+ }
+
+ // prepare adapter ctor
+ const jstring addr = from_string_to_jstring(env, adapter->getAddressString());
+ const jstring name = from_string_to_jstring(env, adapter->getName());
+ const jclass clazz = search_class(env, *adapter);
+ if( nullptr == clazz ) {
+ throw InternalError("Adapter class not found: "+HCIAdapter::java_class(), E_FILE_LINE);
+ }
+ const jmethodID clazz_ctor = search_method(env, clazz, "<init>", _adapterClazzCtorArgs.c_str(), false);
+ if( nullptr == clazz_ctor ) {
+ throw InternalError("Adapter ctor not found: "+HCIAdapter::java_class()+".<init>"+_adapterClazzCtorArgs, E_FILE_LINE);
+ }
+ exception_check_raise_and_throw(env, E_FILE_LINE);
+ jobject jAdapter = env->NewObject(clazz, clazz_ctor, (jlong)adapter, addr, name);
+ exception_check_raise_and_throw(env, E_FILE_LINE);
+ JNIGlobalRef::check(jAdapter, E_FILE_LINE);
+ std::shared_ptr<JavaAnonObj> jAdapterRef = adapter->getJavaObject();
+ JavaGlobalObj::check(jAdapterRef, E_FILE_LINE);
+
+ DBG_PRINT("Java_direct_1bt_tinyb_Manager_getDefaultAdapterImpl: New Adapter %s", adapter->toString().c_str());
+ return JavaGlobalObj::GetObject(jAdapterRef);
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+ return NULL;
+}
+
diff --git a/java/jni/direct_bt/DBTNativeDownlink.cxx b/java/jni/direct_bt/DBTNativeDownlink.cxx
new file mode 100644
index 00000000..201d0728
--- /dev/null
+++ b/java/jni/direct_bt/DBTNativeDownlink.cxx
@@ -0,0 +1,58 @@
+/*
+ * 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_tinyb_NativeDownlink.h"
+
+// #define VERBOSE_ON 1
+#include <dbt_debug.hpp>
+
+#include "JNIMem.hpp"
+#include "helper_base.hpp"
+#include "helper_dbt.hpp"
+
+#include "direct_bt/HCITypes.hpp"
+
+using namespace direct_bt;
+
+void Java_direct_1bt_tinyb_NativeDownlink_initNativeJavaObject(JNIEnv *env, jobject obj, jlong nativeInstance)
+{
+ try {
+ JavaUplink *javaUplink = castInstance<JavaUplink>(nativeInstance);
+ std::shared_ptr<JavaGlobalObj> jobjRef( new JavaGlobalObj(obj) );
+ javaUplink->setJavaObject( jobjRef );
+ JavaGlobalObj::check(javaUplink->getJavaObject(), E_FILE_LINE);
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+}
+
+void Java_direct_1bt_tinyb_NativeDownlink_clearNativeJavaObject(JNIEnv *env, jobject obj, jlong nativeInstance)
+{
+ (void)obj;
+ try {
+ JavaUplink *javaUplink = castInstance<JavaUplink>(nativeInstance);
+ DBG_PRINT("Java_direct_1bt_tinyb_NativeDownlink_clearNativeJavaObject %s", javaUplink->toString().c_str());
+ javaUplink->setJavaObject(nullptr);
+ } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e)
+}
+
diff --git a/java/jni/HCIGattService.cxx b/java/jni/direct_bt/DBTObject.cxx
index 14dfcbe8..74f40e8a 100644
--- a/java/jni/HCIGattService.cxx
+++ b/java/jni/direct_bt/DBTObject.cxx
@@ -23,12 +23,12 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "direct_bt/HCITypes.hpp"
-
-#include "tinyb_hci_HCIGattService.h"
+// #include "direct_bt_tinyb_DBTObject.h"
#include "JNIMem.hpp"
#include "helper_base.hpp"
+#include "direct_bt/HCITypes.hpp"
+
using namespace direct_bt;
diff --git a/java/jni/direct_bt/helper_dbt.cxx b/java/jni/direct_bt/helper_dbt.cxx
new file mode 100644
index 00000000..b3431edc
--- /dev/null
+++ b/java/jni/direct_bt/helper_dbt.cxx
@@ -0,0 +1,65 @@
+/*
+ * 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 <jni.h>
+#include <memory>
+#include <stdexcept>
+#include <vector>
+
+#include "helper_dbt.hpp"
+
+using namespace direct_bt;
+
+jclass direct_bt::search_class(JNIEnv *env, JavaUplink &object)
+{
+ return search_class(env, object.get_java_class().c_str());
+}
+
+#if 0
+
+jobject direct_bt::convert_vector_to_jobject(JNIEnv *env, std::vector<std::shared_ptr<JavaUplink>>& array)
+{
+ unsigned int array_size = array.size();
+
+ jmethodID arraylist_add;
+ jobject result = get_new_arraylist(env, array_size, &arraylist_add);
+
+ if (0 == array_size) {
+ return result;
+ }
+
+ for (unsigned int i = 0; i < array_size; ++i) {
+ std::shared_ptr<JavaUplink> elem = array.at(i);
+ std::shared_ptr<JNIGlobalRef> objref = elem->getJavaObject();
+ if ( nullptr == objref ) {
+ throw InternalError("JavaUplink element of array has no valid java-object: "+elem->toString(), E_FILE_LINE);
+ }
+ env->CallBooleanMethod(result, arraylist_add, objref->get());
+ }
+ return result;
+}
+
+#endif
+
diff --git a/java/jni/direct_bt/helper_dbt.hpp b/java/jni/direct_bt/helper_dbt.hpp
new file mode 100644
index 00000000..2f3d265f
--- /dev/null
+++ b/java/jni/direct_bt/helper_dbt.hpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef HELPER_DBT_HPP_
+#define HELPER_DBT_HPP_
+
+#include "JNIMem.hpp"
+#include "helper_base.hpp"
+
+#include "direct_bt/JavaAccess.hpp"
+#include "direct_bt/BasicTypes.hpp"
+
+namespace direct_bt {
+
+ class JavaGlobalObj : public JavaAnonObj {
+ private:
+ JNIGlobalRef javaObjectRef;
+
+ public:
+ static inline void check(const std::shared_ptr<JavaAnonObj> & shref, const char* file, int line) {
+ if( nullptr == shref ) {
+ throw direct_bt::RuntimeException("JavaGlobalObj::check: Null shared-JavaAnonObj", file, line);
+ }
+ const jobject obj = static_cast<const JavaGlobalObj*>(shref.get())->getObject();
+ if( nullptr == obj ) {
+ throw direct_bt::RuntimeException("JavaGlobalObj::check: Null object", file, line);
+ }
+ }
+ JavaGlobalObj(jobject obj) : javaObjectRef(obj) { }
+ ~JavaGlobalObj() override { }
+
+ std::string toString() const override {
+ const uint64_t ref = (uint64_t)(void*)javaObjectRef.getObject();
+ return "JavaGlobalObj["+uint64HexString(ref, true)+"]";
+ }
+
+ JNIGlobalRef & getJavaObject() { return javaObjectRef; }
+
+ /* Provides access to the stored GlobalRef as an jobject. */
+ jobject getObject() const { return javaObjectRef.getObject(); }
+ /* Provides access to the stored GlobalRef as a jclass. */
+ jclass getClass() const { return javaObjectRef.getClass(); }
+
+ /* Provides access to the stored GlobalRef as an jobject. */
+ static jobject GetObject(const std::shared_ptr<JavaAnonObj> & shref) {
+ return static_cast<JavaGlobalObj*>(shref.get())->getObject();
+ }
+
+ /* Provides access to the stored GlobalRef as a jclass. */
+ static jclass GetClass(const std::shared_ptr<JavaAnonObj> & shref) {
+ return static_cast<JavaGlobalObj*>(shref.get())->getClass();
+ }
+ };
+
+
+ jclass search_class(JNIEnv *env, JavaUplink &object);
+
+#if 0
+
+ jobject convert_vector_to_jobject(JNIEnv *env, std::vector<std::shared_ptr<JavaUplink>>& array);
+
+#else
+
+ template <typename T>
+ jobject convert_vector_to_jobject(JNIEnv *env, std::vector<std::shared_ptr<T>>& array)
+ {
+ unsigned int array_size = array.size();
+
+ jmethodID arraylist_add;
+ jobject result = get_new_arraylist(env, array_size, &arraylist_add);
+
+ if (0 == array_size) {
+ return result;
+ }
+
+ for (unsigned int i = 0; i < array_size; ++i) {
+ std::shared_ptr<T> elem = array.at(i);
+ std::shared_ptr<JavaAnonObj> objref = elem->getJavaObject();
+ if ( nullptr == objref ) {
+ throw InternalError("JavaUplink element of array has no valid java-object: "+elem->toString(), E_FILE_LINE);
+ }
+ env->CallBooleanMethod(result, arraylist_add, JavaGlobalObj::GetObject(objref));
+ }
+ return result;
+ }
+
+#endif
+
+} // namespace direct_bt
+
+#endif /* HELPER_DBT_HPP_ */
diff --git a/java/jni/helper_base.cxx b/java/jni/helper_base.cxx
index 2c0c23e6..dd3dcf54 100644
--- a/java/jni/helper_base.cxx
+++ b/java/jni/helper_base.cxx
@@ -31,7 +31,9 @@
#include <stdexcept>
#include <vector>
-#include "helper_tinyb.hpp"
+#include "helper_base.hpp"
+
+#define JAVA_MAIN_PACKAGE "org/tinyb"
jfieldID getInstanceField(JNIEnv *env, jobject obj)
{
@@ -144,6 +146,11 @@ std::string from_jstring_to_string(JNIEnv *env, jstring str)
return string_to_write;
}
+jstring from_string_to_jstring(JNIEnv *env, const std::string & str)
+{
+ return env->NewStringUTF(str.c_str());
+}
+
jobject get_bluetooth_type(JNIEnv *env, const char *field_name)
{
jclass b_type_enum = search_class(env, JAVA_MAIN_PACKAGE "/BluetoothType");
@@ -182,6 +189,10 @@ void raise_java_runtime_exception(JNIEnv *env, std::runtime_error &e)
env->ThrowNew(env->FindClass("java/lang/RuntimeException"), e.what());
}
+void raise_java_runtime_exception(JNIEnv *env, direct_bt::RuntimeException &e) {
+ env->ThrowNew(env->FindClass("java/lang/RuntimeException"), e.what());
+}
+
void raise_java_oom_exception(JNIEnv *env, std::bad_alloc &e)
{
env->ThrowNew(env->FindClass("java/lang/OutOfMemoryException"), e.what());
@@ -192,4 +203,18 @@ void raise_java_invalid_arg_exception(JNIEnv *env, std::invalid_argument &e)
env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), e.what());
}
+void raise_java_bluetooth_exception(JNIEnv *env, direct_bt::BluetoothException &e)
+{
+ env->ThrowNew(env->FindClass("org/tinyb/BluetoothException"), e.what());
+}
+void exception_check_raise_and_throw(JNIEnv *env, const char* file, int line)
+{
+ if( env->ExceptionCheck() ) {
+ env->ExceptionDescribe();
+ jthrowable e = env->ExceptionOccurred();
+ env->ExceptionClear();
+ env->Throw(e);
+ throw direct_bt::RuntimeException("Java exception occurred and forwarded.", file, line);
+ }
+}
diff --git a/java/jni/helper_base.hpp b/java/jni/helper_base.hpp
index 153faa9b..4cbda995 100644
--- a/java/jni/helper_base.hpp
+++ b/java/jni/helper_base.hpp
@@ -26,10 +26,15 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#pragma once
+#ifndef HELPER_BASE_HPP_
+#define HELPER_BASE_HPP_
#include <vector>
#include <memory>
+#include <functional>
+#include <jni.h>
+
+#include "BasicTypes.hpp"
jfieldID getInstanceField(JNIEnv *env, jobject obj);
@@ -41,10 +46,20 @@ jfieldID search_field(JNIEnv *env, jclass clazz, const char *field_name,
const char *type, bool is_static);
bool from_jboolean_to_bool(jboolean val);
std::string from_jstring_to_string(JNIEnv *env, jstring str);
+jstring from_string_to_jstring(JNIEnv *env, const std::string & str);
jobject get_bluetooth_type(JNIEnv *env, const char *field_name);
jobject get_new_arraylist(JNIEnv *env, unsigned int size, jmethodID *add);
template <typename T>
+T *castInstance(jlong instance)
+{
+ T *t = reinterpret_cast<T *>(instance);
+ if (t == nullptr)
+ throw std::runtime_error("Trying to cast null object");
+ return t;
+}
+
+template <typename T>
T *getInstance(JNIEnv *env, jobject obj)
{
jlong instance = env->GetLongField(obj, getInstanceField(env, obj));
@@ -111,7 +126,58 @@ jobject convert_vector_to_jobject(JNIEnv *env, std::vector<std::unique_ptr<T>>&
return result;
}
+template <typename T>
+jobject convert_vector_to_jobject(JNIEnv *env, std::vector<std::shared_ptr<T>>& array,
+ const char *ctor_prototype, std::function<jobject(JNIEnv*, jclass, jmethodID, T*)> ctor)
+{
+ unsigned int array_size = array.size();
+
+ jmethodID arraylist_add;
+ jobject result = get_new_arraylist(env, array_size, &arraylist_add);
+
+ if (array_size == 0)
+ {
+ return result;
+ }
+
+ jclass clazz = search_class(env, T::java_class().c_str());
+ jmethodID clazz_ctor = search_method(env, clazz, "<init>", ctor_prototype, false);
+
+ for (unsigned int i = 0; i < array_size; ++i)
+ {
+ T *elem = array.at(i).get();
+ jobject object = ctor(env, clazz, clazz_ctor, elem);
+ if (!object)
+ {
+ throw std::runtime_error("cannot create instance of class\n");
+ }
+ env->CallBooleanMethod(result, arraylist_add, object);
+ }
+ return result;
+}
+
void raise_java_exception(JNIEnv *env, std::exception &e);
void raise_java_runtime_exception(JNIEnv *env, std::runtime_error &e);
+void raise_java_runtime_exception(JNIEnv *env, direct_bt::RuntimeException &e);
void raise_java_oom_exception(JNIEnv *env, std::bad_alloc &e);
void raise_java_invalid_arg_exception(JNIEnv *env, std::invalid_argument &e);
+void raise_java_bluetooth_exception(JNIEnv *env, direct_bt::BluetoothException &e);
+
+void exception_check_raise_and_throw(JNIEnv *env, const char* file, int line);
+
+#define CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) \
+ catch (std::bad_alloc &e) { \
+ raise_java_oom_exception(env, e); \
+} catch (direct_bt::BluetoothException &e) { \
+ raise_java_bluetooth_exception(env, e); \
+} catch (direct_bt::RuntimeException &e) { \
+ raise_java_runtime_exception(env, e); \
+} catch (std::runtime_error &e) { \
+ raise_java_runtime_exception(env, e); \
+} catch (std::invalid_argument &e) { \
+ raise_java_invalid_arg_exception(env, e); \
+} catch (std::exception &e) { \
+ raise_java_exception(env, e); \
+}
+
+#endif /* HELPER_BASE_HPP_ */
diff --git a/java/jni/tinyb/CMakeLists.txt b/java/jni/tinyb/CMakeLists.txt
new file mode 100644
index 00000000..a2bfb5a7
--- /dev/null
+++ b/java/jni/tinyb/CMakeLists.txt
@@ -0,0 +1,54 @@
+find_package(JNI REQUIRED)
+
+if (JNI_FOUND)
+ message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}")
+ message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}")
+endif (JNI_FOUND)
+
+set (tinyb_LIB_INCLUDE_DIRS
+ ${PROJECT_SOURCE_DIR}/api
+ ${PROJECT_SOURCE_DIR}/api/direct_bt
+ ${PROJECT_SOURCE_DIR}/api/tinyb
+ ${PROJECT_SOURCE_DIR}/include
+ ${PROJECT_SOURCE_DIR}/java/jni
+)
+
+include_directories(
+ ${JNI_INCLUDE_DIRS}
+ ${tinyb_LIB_INCLUDE_DIRS}
+ ${JNI_HEADER_PATH}
+)
+
+set (tinyb_JNI_SRCS
+ ${PROJECT_SOURCE_DIR}/src/direct_bt/BasicTypes.cpp
+ ${PROJECT_SOURCE_DIR}/java/jni/JNIMem.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/helper_base.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/BluetoothFactory.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/BluetoothUtils.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/tinyb/helper_tinyb.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusAdapter.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusDevice.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusEvent.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusGattCharacteristic.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusGattDescriptor.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusGattService.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusManager.cxx
+ ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusObject.cxx
+)
+
+set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed")
+
+add_library (javatinyb SHARED ${tinyb_JNI_SRCS})
+target_link_libraries(javatinyb ${JNI_LIBRARIES} tinyb)
+
+set_target_properties(
+ javatinyb
+ PROPERTIES
+ SOVERSION ${tinyb_VERSION_MAJOR}
+ VERSION ${tinyb_VERSION_STRING}
+ CXX_STANDARD 11
+ COMPILE_FLAGS "-Wall -Wextra"
+)
+
+install(TARGETS javatinyb LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
diff --git a/java/jni/DBusAdapter.cxx b/java/jni/tinyb/DBusAdapter.cxx
index 9f43c4b8..9f43c4b8 100644
--- a/java/jni/DBusAdapter.cxx
+++ b/java/jni/tinyb/DBusAdapter.cxx
diff --git a/java/jni/DBusDevice.cxx b/java/jni/tinyb/DBusDevice.cxx
index 6a833356..6a833356 100644
--- a/java/jni/DBusDevice.cxx
+++ b/java/jni/tinyb/DBusDevice.cxx
diff --git a/java/jni/DBusEvent.cxx b/java/jni/tinyb/DBusEvent.cxx
index 14b6431c..14b6431c 100644
--- a/java/jni/DBusEvent.cxx
+++ b/java/jni/tinyb/DBusEvent.cxx
diff --git a/java/jni/DBusGattCharacteristic.cxx b/java/jni/tinyb/DBusGattCharacteristic.cxx
index 43ac754f..43ac754f 100644
--- a/java/jni/DBusGattCharacteristic.cxx
+++ b/java/jni/tinyb/DBusGattCharacteristic.cxx
diff --git a/java/jni/DBusGattDescriptor.cxx b/java/jni/tinyb/DBusGattDescriptor.cxx
index 2118205c..2118205c 100644
--- a/java/jni/DBusGattDescriptor.cxx
+++ b/java/jni/tinyb/DBusGattDescriptor.cxx
diff --git a/java/jni/DBusGattService.cxx b/java/jni/tinyb/DBusGattService.cxx
index 0ab089f2..0ab089f2 100644
--- a/java/jni/DBusGattService.cxx
+++ b/java/jni/tinyb/DBusGattService.cxx
diff --git a/java/jni/DBusManager.cxx b/java/jni/tinyb/DBusManager.cxx
index 1680e866..1680e866 100644
--- a/java/jni/DBusManager.cxx
+++ b/java/jni/tinyb/DBusManager.cxx
diff --git a/java/jni/DBusObject.cxx b/java/jni/tinyb/DBusObject.cxx
index 8e3b93a2..8e3b93a2 100644
--- a/java/jni/DBusObject.cxx
+++ b/java/jni/tinyb/DBusObject.cxx
diff --git a/java/jni/helper_tinyb.cxx b/java/jni/tinyb/helper_tinyb.cxx
index 865d55e5..c20b5933 100644
--- a/java/jni/helper_tinyb.cxx
+++ b/java/jni/tinyb/helper_tinyb.cxx
@@ -33,76 +33,78 @@
#include "helper_tinyb.hpp"
-jclass search_class(JNIEnv *env, tinyb::BluetoothObject &object)
+using namespace tinyb;
+
+jclass search_class(JNIEnv *env, BluetoothObject &object)
{
return search_class(env, object.get_java_class().c_str());
}
-tinyb::BluetoothType from_int_to_btype(int type)
+BluetoothType from_int_to_btype(int type)
{
- tinyb::BluetoothType result = tinyb::BluetoothType::NONE;
+ BluetoothType result = BluetoothType::NONE;
switch (type)
{
case 0:
- result = tinyb::BluetoothType::NONE;
+ result = BluetoothType::NONE;
break;
case 1:
- result = tinyb::BluetoothType::ADAPTER;
+ result = BluetoothType::ADAPTER;
break;
case 2:
- result = tinyb::BluetoothType::DEVICE;
+ result = BluetoothType::DEVICE;
break;
case 3:
- result = tinyb::BluetoothType::GATT_SERVICE;
+ result = BluetoothType::GATT_SERVICE;
break;
case 4:
- result = tinyb::BluetoothType::GATT_CHARACTERISTIC;
+ result = BluetoothType::GATT_CHARACTERISTIC;
break;
case 5:
- result = tinyb::BluetoothType::GATT_CHARACTERISTIC;
+ result = BluetoothType::GATT_CHARACTERISTIC;
break;
default:
- result = tinyb::BluetoothType::NONE;
+ result = BluetoothType::NONE;
break;
}
return result;
}
-tinyb::TransportType from_int_to_transport_type(int type)
+TransportType from_int_to_transport_type(int type)
{
- tinyb::TransportType result = tinyb::TransportType::AUTO;
+ TransportType result = TransportType::AUTO;
switch (type)
{
case 0:
- result = tinyb::TransportType::AUTO;
+ result = TransportType::AUTO;
break;
case 1:
- result = tinyb::TransportType::BREDR;
+ result = TransportType::BREDR;
break;
case 2:
- result = tinyb::TransportType::LE;
+ result = TransportType::LE;
break;
default:
- result = tinyb::TransportType::AUTO;
+ result = TransportType::AUTO;
break;
}
return result;
}
-void raise_java_bluetooth_exception(JNIEnv *env, tinyb::BluetoothException &e)
+void raise_java_bluetooth_exception(JNIEnv *env, BluetoothException &e)
{
env->ThrowNew(env->FindClass("org/tinyb/BluetoothException"), e.what());
}
diff --git a/java/jni/helper_tinyb.hpp b/java/jni/tinyb/helper_tinyb.hpp
index f1873a7f..d91051c4 100644
--- a/java/jni/helper_tinyb.hpp
+++ b/java/jni/tinyb/helper_tinyb.hpp
@@ -32,8 +32,12 @@
#include "tinyb/BluetoothObject.hpp"
#include "tinyb/BluetoothException.hpp"
-jclass search_class(JNIEnv *env, tinyb::BluetoothObject &object);
-tinyb::BluetoothType from_int_to_btype(int type);
-tinyb::TransportType from_int_to_transport_type(int type);
+namespace tinyb {
-void raise_java_bluetooth_exception(JNIEnv *env, tinyb::BluetoothException &e);
+ jclass search_class(JNIEnv *env, BluetoothObject &object);
+ BluetoothType from_int_to_btype(int type);
+ TransportType from_int_to_transport_type(int type);
+
+ void raise_java_bluetooth_exception(JNIEnv *env, BluetoothException &e);
+
+} // namespace tinyb
diff --git a/java/org/tinyb/BluetoothAdapter.java b/java/org/tinyb/BluetoothAdapter.java
index 95d2e6d0..2b55cf75 100644
--- a/java/org/tinyb/BluetoothAdapter.java
+++ b/java/org/tinyb/BluetoothAdapter.java
@@ -242,6 +242,12 @@ public interface BluetoothAdapter extends BluetoothObject
public boolean getDiscovering();
/**
+ * Sets the {@link BluetoothDeviceDiscoveryListener} for the respective device discovery events.
+ * @param listener A {@link BluetoothDeviceDiscoveryListener} instance, or {@code null} to disable notifications.
+ */
+ public void setDeviceDiscoveryListener(final BluetoothDeviceDiscoveryListener listener);
+
+ /**
* Enables notifications for the discovering property and calls run function of the
* BluetoothNotification object.
* @param callback A BluetoothNotification<Boolean> object. Its run function will be called
diff --git a/java/org/tinyb/BluetoothDeviceDiscoveryListener.java b/java/org/tinyb/BluetoothDeviceDiscoveryListener.java
new file mode 100644
index 00000000..737f47b9
--- /dev/null
+++ b/java/org/tinyb/BluetoothDeviceDiscoveryListener.java
@@ -0,0 +1,42 @@
+/**
+ * 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.
+ */
+
+package org.tinyb;
+
+/**
+ * {@link BluetoothDevice} listener for the respective {@link BluetoothDevice} discovery events: Added, updated and removed.
+ * <p>
+ * A listener instance may be attached to a {@link BluetoothAdapter} via
+ * {@link BluetoothAdapter#setDeviceDiscoveryListener(BluetoothDeviceDiscoveryListener)}.
+ * </p>
+ */
+public interface BluetoothDeviceDiscoveryListener {
+ /** A {@link BluetoothDevice} has been newly discovered. */
+ public void deviceAdded(final BluetoothAdapter adapter, final BluetoothDevice device);
+ /** An already discovered {@link BluetoothDevice} has been updated. */
+ public void deviceUpdated(final BluetoothAdapter adapter, final BluetoothDevice device);
+ /** An already discovered {@link BluetoothDevice} has been removed or lost. */
+ public void deviceRemoved(final BluetoothAdapter adapter, final BluetoothDevice device);
+};
diff --git a/java/org/tinyb/BluetoothFactory.java b/java/org/tinyb/BluetoothFactory.java
index 8f01db15..38306a16 100644
--- a/java/org/tinyb/BluetoothFactory.java
+++ b/java/org/tinyb/BluetoothFactory.java
@@ -39,12 +39,12 @@ public class BluetoothFactory {
/**
* Name of the native implementation native library basename: {@value}
*/
- public static final String ImplNativeLibBasename = "tinyb";
+ public static final String ImplNativeLibBasename = "direct_bt"; // "tinyb";
/**
* Name of the Jave native library basename: {@value}
*/
- public static final String JavaNativeLibBasename = "javatinyb";
+ public static final String JavaNativeLibBasename = "javadirect_bt"; // "javatinyb";
/**
* Manifest's {@link Attributes.Name#SPECIFICATION_VERSION} or {@code null} if not available.
@@ -138,12 +138,12 @@ public class BluetoothFactory {
public static final String DBusFactoryImplClassName = "tinyb.dbus.DBusManager";
/**
- * Fully qualified factory class name for native HCI implementation: {@value}
+ * Fully qualified factory class name for direct_bt implementation: {@value}
* <p>
* This value is exposed for convenience, user implementations are welcome.
* </p>
*/
- public static final String HCIFactoryImplClassName = "tinyb.hci.HCIManager";
+ public static final String DirectBTFactoryImplClassName = "direct_bt.tinyb.Manager";
/**
* Returns an initialized BluetoothManager instance using the given {@code factoryImplClass}.
@@ -187,7 +187,7 @@ public class BluetoothFactory {
* @throws InvocationTargetException
* @throws ClassNotFoundException
* @see {@link #DBusFactoryImplClassName}
- * @see {@link #HCIFactoryImplClassName}
+ * @see {@link #DirectBTFactoryImplClassName}
*/
public static synchronized BluetoothManager getBluetoothManager(final String factoryImplClassName)
throws BluetoothException, NoSuchMethodException, SecurityException,
diff --git a/java/org/tinyb/BluetoothManager.java b/java/org/tinyb/BluetoothManager.java
index ec1de2d7..b7bec3cb 100644
--- a/java/org/tinyb/BluetoothManager.java
+++ b/java/org/tinyb/BluetoothManager.java
@@ -181,4 +181,13 @@ public interface BluetoothManager
* @return TRUE if discovery is running
*/
public boolean getDiscovering() throws BluetoothException;
+
+ /**
+ * Release the native memory associated with this object and all related Bluetooth resources.
+ * The object should not be used following a call to close
+ * <p>
+ * Shutdown method is intended to allow a clean Bluetooth state at program exist.
+ * </p>
+ */
+ public void shutdown();
}
diff --git a/java/jni/HCIDevice.cxx b/java/org/tinyb/BluetoothUtils.java
index d143b85d..e7a0276b 100644
--- a/java/jni/HCIDevice.cxx
+++ b/java/org/tinyb/BluetoothUtils.java
@@ -1,4 +1,4 @@
-/*
+/**
* Author: Sven Gothel <[email protected]>
* Copyright (c) 2020 Gothel Software e.K.
* Copyright (c) 2020 ZAFENA AB
@@ -22,13 +22,13 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+package org.tinyb;
-#include "direct_bt/HCITypes.hpp"
+public class BluetoothUtils {
-#include "tinyb_hci_HCIDevice.h"
-
-#include "JNIMem.hpp"
-#include "helper_base.hpp"
-
-using namespace direct_bt;
+ /**
+ * Returns current monotonic time in milliseconds.
+ */
+ public static native long getCurrentMilliseconds();
+}
diff --git a/java/tinyb/dbus/DBusAdapter.java b/java/tinyb/dbus/DBusAdapter.java
index 695677fe..973d3e8d 100644
--- a/java/tinyb/dbus/DBusAdapter.java
+++ b/java/tinyb/dbus/DBusAdapter.java
@@ -35,6 +35,7 @@ import java.util.UUID;
import org.tinyb.BluetoothAdapter;
import org.tinyb.BluetoothDevice;
+import org.tinyb.BluetoothDeviceDiscoveryListener;
import org.tinyb.BluetoothException;
import org.tinyb.BluetoothManager;
import org.tinyb.BluetoothNotification;
@@ -148,6 +149,11 @@ public class DBusAdapter extends DBusObject implements BluetoothAdapter
public native boolean getDiscovering();
@Override
+ public void setDeviceDiscoveryListener(final BluetoothDeviceDiscoveryListener l) {
+ throw new UnsupportedOperationException(); // FIXME
+ }
+
+ @Override
public native void enableDiscoveringNotifications(BluetoothNotification<Boolean> callback);
@Override
diff --git a/java/tinyb/dbus/DBusManager.java b/java/tinyb/dbus/DBusManager.java
index 2b5efe65..bfcd5e4b 100644
--- a/java/tinyb/dbus/DBusManager.java
+++ b/java/tinyb/dbus/DBusManager.java
@@ -134,4 +134,9 @@ public class DBusManager implements BluetoothManager
{
delete();
}
+
+ @Override
+ public void shutdown() {
+ delete();
+ }
}
diff --git a/java/tinyb/hci/HCIAdapter.java b/java/tinyb/hci/HCIAdapter.java
deleted file mode 100644
index 71c9d818..00000000
--- a/java/tinyb/hci/HCIAdapter.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/**
- * 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.
- */
-
-package tinyb.hci;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
-
-import org.tinyb.BluetoothAdapter;
-import org.tinyb.BluetoothDevice;
-import org.tinyb.BluetoothException;
-import org.tinyb.BluetoothManager;
-import org.tinyb.BluetoothNotification;
-import org.tinyb.BluetoothType;
-import org.tinyb.TransportType;
-
-public class HCIAdapter extends HCIObject implements BluetoothAdapter
-{
- private final String address;
- private final String name;
-
- /* pp */ HCIAdapter(final String address, final String name)
- {
- super(compHash(address, name));
- this.address = address;
- this.name = name;
- }
-
- @Override
- public boolean equals(final Object obj)
- {
- if (obj == null || !(obj instanceof HCIDevice)) {
- return false;
- }
- final HCIAdapter other = (HCIAdapter)obj;
- return address.equals(other.address) && name.equals(other.name);
- }
-
- @Override
- public String getAddress() { return address; }
-
- @Override
- public String getName() { return name; }
-
- public String getInterfaceName() {
- throw new UnsupportedOperationException(); // FIXME
- }
-
- @Override
- public native BluetoothType getBluetoothType();
-
- @Override
- public native BluetoothAdapter clone();
-
- static BluetoothType class_type() { return BluetoothType.ADAPTER; }
-
- @Override
- public BluetoothDevice find(final String name, final String address, final long timeoutMS) {
- final BluetoothManager manager = HCIManager.getBluetoothManager();
- return (BluetoothDevice) manager.find(BluetoothType.DEVICE, name, address, this, timeoutMS);
- }
-
- @Override
- public BluetoothDevice find(final String name, final String address) {
- return find(name, address, 0);
- }
-
- /* D-Bus method calls: */
-
- @Override
- public native boolean startDiscovery() throws BluetoothException;
-
- @Override
- public native boolean stopDiscovery() throws BluetoothException;
-
- @Override
- public native List<BluetoothDevice> getDevices();
-
- @Override
- public native int removeDevices() throws BluetoothException;
-
- /* D-Bus property accessors: */
-
- @Override
- public native String getAlias();
-
- @Override
- public native void setAlias(String value);
-
- @Override
- public native long getBluetoothClass();
-
- @Override
- public native boolean getPowered();
-
- @Override
- public native void enablePoweredNotifications(BluetoothNotification<Boolean> callback);
-
- @Override
- public native void disablePoweredNotifications();
-
- @Override
- public native void setPowered(boolean value);
-
- @Override
- public native boolean getDiscoverable();
-
- @Override
- public native void enableDiscoverableNotifications(BluetoothNotification<Boolean> callback);
-
- @Override
- public native void disableDiscoverableNotifications();
-
- @Override
- public native void setDiscoverable(boolean value);
-
- @Override
- public native long getDiscoverableTimeout();
-
- @Override
- public native void setDiscoverableTimout(long value);
-
- @Override
- public native BluetoothDevice connectDevice(String address, String addressType);
-
- @Override
- public native boolean getPairable();
-
- @Override
- public native void enablePairableNotifications(BluetoothNotification<Boolean> callback);
-
- @Override
- public native void disablePairableNotifications();
-
- @Override
- public native void setPairable(boolean value);
-
- @Override
- public native long getPairableTimeout();
-
- @Override
- public native void setPairableTimeout(long value);
-
- @Override
- public native boolean getDiscovering();
-
- @Override
- public native void enableDiscoveringNotifications(BluetoothNotification<Boolean> callback);
-
- @Override
- public native void disableDiscoveringNotifications();
-
- @Override
- public native String[] getUUIDs();
-
- @Override
- public native String getModalias();
-
- @Override
- public void setDiscoveryFilter(final List<UUID> uuids, final int rssi, final int pathloss, final TransportType transportType) {
- final List<String> uuidsFmt = new ArrayList<>(uuids.size());
- for (final UUID uuid : uuids) {
- uuidsFmt.add(uuid.toString());
- }
- setDiscoveryFilter(uuidsFmt, rssi, pathloss, transportType.ordinal());
- }
-
- public void setRssiDiscoveryFilter(final int rssi) {
- setDiscoveryFilter(Collections.EMPTY_LIST, rssi, 0, TransportType.AUTO);
- }
-
- private native void delete();
-
- private native void setDiscoveryFilter(List<String> uuids, int rssi, int pathloss, int transportType);
-}
diff --git a/scripts/run-dbt_scanner.sh b/scripts/run-dbt_scanner.sh
index c69b4343..bbeb6968 100755
--- a/scripts/run-dbt_scanner.sh
+++ b/scripts/run-dbt_scanner.sh
@@ -1,5 +1,9 @@
#!/bin/sh
+#
+# ../scripts/run-dbt_scanner.sh -wait -mac C0:26:DA:01:DA:B1 2>&1 | tee ~/dbt_scanner.log
+#
+
if [ ! -e bin/dbt_scanner -o ! -e lib/libtinyb.so -o ! -e lib/libdirect_bt.so ] ; then
echo run from dist directory
exit 1
diff --git a/scripts/run-java-scanner.sh b/scripts/run-java-scanner.sh
deleted file mode 100755
index d4f40875..00000000
--- a/scripts/run-java-scanner.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-
-if [ ! -e lib/java/tinyb2.jar -o ! -e bin/java/ScannerTinyB.jar -o ! -e lib/libtinyb.so -o ! -e lib/libdirect_bt.so ] ; then
- echo run from dist directory
- exit 1
-fi
-java -cp lib/java/tinyb2.jar:bin/java/ScannerTinyB.jar -Djava.library.path=`pwd`/lib ScannerTinyB $*
diff --git a/scripts/run-java-scanner00.sh b/scripts/run-java-scanner00.sh
new file mode 100755
index 00000000..509b5d79
--- /dev/null
+++ b/scripts/run-java-scanner00.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if [ ! -e lib/java/tinyb2.jar -o ! -e bin/java/ScannerTinyB00.jar -o ! -e lib/libtinyb.so -o ! -e lib/libdirect_bt.so ] ; then
+ echo run from dist directory
+ exit 1
+fi
+java -cp lib/java/tinyb2.jar:bin/java/ScannerTinyB00.jar -Djava.library.path=`pwd`/lib ScannerTinyB00 $*
diff --git a/scripts/run-java-scanner01.sh b/scripts/run-java-scanner01.sh
new file mode 100755
index 00000000..fec669f2
--- /dev/null
+++ b/scripts/run-java-scanner01.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+#
+# ../scripts/run-java-scanner01.sh -mac C0:26:DA:01:DA:B1 -mode 0 2>&1 | tee ~/dbt_scanner_java.log
+#
+
+if [ ! -e lib/java/tinyb2.jar -o ! -e bin/java/ScannerTinyB01.jar -o ! -e lib/libtinyb.so -o ! -e lib/libdirect_bt.so ] ; then
+ echo run from dist directory
+ exit 1
+fi
+java -cp lib/java/tinyb2.jar:bin/java/ScannerTinyB01.jar -Djava.library.path=`pwd`/lib ScannerTinyB01 $*
diff --git a/src/direct_bt/ATTPDUTypes.cpp b/src/direct_bt/ATTPDUTypes.cpp
index d32667a2..88747d25 100644
--- a/src/direct_bt/ATTPDUTypes.cpp
+++ b/src/direct_bt/ATTPDUTypes.cpp
@@ -23,6 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dbt_debug.hpp>
#include <cstring>
#include <string>
#include <memory>
@@ -34,7 +35,6 @@
#include "ATTPDUTypes.hpp"
-#include "dbt_debug.hpp"
using namespace direct_bt;
diff --git a/src/direct_bt/BTTypes.cpp b/src/direct_bt/BTTypes.cpp
index bfd955f6..bb79ad14 100644
--- a/src/direct_bt/BTTypes.cpp
+++ b/src/direct_bt/BTTypes.cpp
@@ -23,6 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dbt_debug.hpp>
#include <cstring>
#include <string>
#include <memory>
@@ -34,7 +35,6 @@
#include "BTTypes.hpp"
-#include "dbt_debug.hpp"
std::string EUI48::toString() const {
const int length = 17;
diff --git a/src/direct_bt/BasicTypes.cpp b/src/direct_bt/BasicTypes.cpp
index aa848b7e..6bda705c 100644
--- a/src/direct_bt/BasicTypes.cpp
+++ b/src/direct_bt/BasicTypes.cpp
@@ -38,7 +38,7 @@ extern "C" {
}
#endif
-#include "dbt_debug.hpp"
+#include <dbt_debug.hpp>
using namespace direct_bt;
@@ -59,21 +59,23 @@ int64_t direct_bt::getCurrentMilliseconds() {
return t.tv_sec * MilliPerOne + t.tv_nsec / NanoPerMilli;
}
-const char* RuntimeException::what() const noexcept {
+const char* direct_bt::RuntimeException::what() const noexcept {
#if _USE_BACKTRACE_
+ // std::string out(std::runtime_error::what());
std::string out(msg);
void *buffers[10];
size_t nptrs = backtrace(buffers, 10);
char **symbols = backtrace_symbols(buffers, nptrs);
if( NULL != symbols ) {
out.append("\nBacktrace:\n");
- for(int i=0; i<nptrs; i++) {
+ for(size_t i=0; i<nptrs; i++) {
out.append(symbols[i]).append("\n");
}
free(symbols);
}
return out.c_str();
#else
+ // return std::runtime_error::what();
return msg.c_str();
#endif
}
@@ -195,6 +197,19 @@ std::string direct_bt::uint32HexString(const uint32_t v, const bool leading0X) {
return str;
}
+std::string direct_bt::uint64HexString(const uint64_t v, const bool leading0X) {
+ const int length = leading0X ? 18 : 16; // ( '0x0000000000000000' | '0000000000000000' )
+ std::string str;
+ str.reserve(length+1); // including EOS for snprintf
+ str.resize(length);
+
+ const int count = snprintf(&str[0], str.capacity(), ( leading0X ? "0x%.16" PRIX64 : "%.16" PRIX64 ), v);
+ if( length != count ) {
+ throw InternalError("uint64_t string not of length "+std::to_string(length)+" but "+std::to_string(count), E_FILE_LINE);
+ }
+ return str;
+}
+
static const char* HEX_ARRAY = "0123456789ABCDEF";
std::string direct_bt::bytesHexString(const uint8_t * bytes, const int offset, const int length, const bool lsbFirst, const bool leading0X) {
diff --git a/src/direct_bt/GATTHandler.cpp b/src/direct_bt/GATTHandler.cpp
index 75370a3e..27183b42 100644
--- a/src/direct_bt/GATTHandler.cpp
+++ b/src/direct_bt/GATTHandler.cpp
@@ -47,7 +47,7 @@ extern "C" {
#include "GATTHandler.hpp"
-#include "dbt_debug.hpp"
+#include <dbt_debug.hpp>
using namespace direct_bt;
diff --git a/src/direct_bt/GATTNumbers.cpp b/src/direct_bt/GATTNumbers.cpp
index 970d94e2..564e5427 100644
--- a/src/direct_bt/GATTNumbers.cpp
+++ b/src/direct_bt/GATTNumbers.cpp
@@ -23,6 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dbt_debug.hpp>
#include <cstring>
#include <string>
#include <memory>
@@ -34,7 +35,6 @@
#include "GATTNumbers.hpp"
-#include "dbt_debug.hpp"
using namespace direct_bt;
diff --git a/src/direct_bt/GATTTypes.cpp b/src/direct_bt/GATTTypes.cpp
index 14a5d3dd..bedc0dba 100644
--- a/src/direct_bt/GATTTypes.cpp
+++ b/src/direct_bt/GATTTypes.cpp
@@ -23,6 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dbt_debug.hpp>
#include <cstring>
#include <string>
#include <memory>
@@ -34,7 +35,6 @@
#include "GATTTypes.hpp"
-#include "dbt_debug.hpp"
using namespace direct_bt;
diff --git a/src/direct_bt/HCIAdapter.cpp b/src/direct_bt/HCIAdapter.cpp
index 2b3d7e51..da9db337 100644
--- a/src/direct_bt/HCIAdapter.cpp
+++ b/src/direct_bt/HCIAdapter.cpp
@@ -32,6 +32,9 @@
#include <algorithm>
+// #define VERBOSE_ON 1
+#include <dbt_debug.hpp>
+
#include "BTIoctl.hpp"
#include "HCIIoctl.hpp"
@@ -44,8 +47,6 @@ extern "C" {
#include <poll.h>
}
-#include "dbt_debug.hpp"
-
using namespace direct_bt;
// *************************************************
@@ -58,6 +59,7 @@ void HCISession::disconnect(const uint8_t reason) {
connectedDevice = nullptr;
if( !hciComm.isLEConnected() ) {
+ DBG_PRINT("HCISession::disconnect: Not connected");
return;
}
if( !hciComm.le_disconnect(reason) ) {
@@ -68,10 +70,12 @@ void HCISession::disconnect(const uint8_t reason) {
bool HCISession::close()
{
if( !hciComm.isOpen() ) {
+ DBG_PRINT("HCISession::close: Not open");
return false;
}
+ DBG_PRINT("HCISession::close: ...");
+ adapter.sessionClosing(*this);
hciComm.close();
- adapter.sessionClosed(*this);
return true;
}
@@ -88,9 +92,9 @@ bool HCIAdapter::validateDevInfo() {
return true;
}
-void HCIAdapter::sessionClosed(HCISession& s)
+void HCIAdapter::sessionClosing(HCISession& s)
{
- (void)s;
+ stopDiscovery(s);
session = nullptr;
}
@@ -113,6 +117,9 @@ HCIAdapter::HCIAdapter(const int dev_id)
}
HCIAdapter::~HCIAdapter() {
+ DBG_PRINT("HCIAdapter::dtor: %s", toString().c_str());
+ deviceDiscoveryListener = nullptr;
+
scannedDevices.clear();
discoveredDevices.clear();
session = nullptr;
@@ -156,8 +163,10 @@ bool HCIAdapter::startDiscovery(HCISession &session, uint8_t own_mac_type,
void HCIAdapter::stopDiscovery(HCISession& session) {
if( !session.isOpen() ) {
+ DBG_PRINT("HCIAdapter::stopDiscovery: Not open");
return;
}
+ DBG_PRINT("HCIAdapter::stopDiscovery: ...");
session.hciComm.le_disable_scan();
}
@@ -213,14 +222,16 @@ bool HCIAdapter::addDiscoveredDevice(std::shared_ptr<HCIDevice> const &device) {
return false;
}
-void HCIAdapter::removeDiscoveredDevices() {
+int HCIAdapter::removeDiscoveredDevices() {
// also need to flush scannedDevices, old data
scannedDevices.clear();
+ int res = discoveredDevices.size();
discoveredDevices.clear();
+ return res;
}
std::string HCIAdapter::toString() const {
- std::string out("Adapter["+getAddressString()+", '"+getName()+"', id="+std::to_string(dev_id)+"]");
+ std::string out("Adapter["+getAddressString()+", '"+getName()+"', id="+std::to_string(dev_id)+", "+javaObjectToString()+"]");
if(discoveredDevices.size() > 0 ) {
out.append("\n");
for(auto it = discoveredDevices.begin(); it != discoveredDevices.end(); it++) {
diff --git a/src/direct_bt/HCIComm.cpp b/src/direct_bt/HCIComm.cpp
index 8768a0ed..a45bf781 100644
--- a/src/direct_bt/HCIComm.cpp
+++ b/src/direct_bt/HCIComm.cpp
@@ -33,6 +33,7 @@
#include <algorithm>
// #define VERBOSE_ON 1
+#include <dbt_debug.hpp>
#include "HCIComm.hpp"
@@ -47,8 +48,6 @@ extern "C" {
#include <poll.h>
}
-#include "dbt_debug.hpp"
-
namespace direct_bt {
int HCIComm::hci_open_dev(const uint16_t dev_id, const uint16_t channel)
diff --git a/src/direct_bt/HCIDevice.cpp b/src/direct_bt/HCIDevice.cpp
index 6abd854a..4ef9354d 100644
--- a/src/direct_bt/HCIDevice.cpp
+++ b/src/direct_bt/HCIDevice.cpp
@@ -23,6 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dbt_debug.hpp>
#include <cstring>
#include <string>
#include <memory>
@@ -35,7 +36,6 @@
#include "HCIComm.hpp"
#include "HCITypes.hpp"
-#include "dbt_debug.hpp"
using namespace direct_bt;
@@ -93,7 +93,7 @@ std::string HCIDevice::toString() const {
std::string msdstr = nullptr != msd ? msd->toString() : "MSD[null]";
std::string out("Device["+getAddressString()+", '"+getName()+
"', 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)+", "+msdstr+"]");
+ ", tx-power "+std::to_string(tx_power)+", "+msdstr+", "+javaObjectToString()+"]");
if(services.size() > 0 ) {
out.append("\n");
int i=0;
diff --git a/src/direct_bt/L2CAPComm.cpp b/src/direct_bt/L2CAPComm.cpp
index e23ffa74..dfa8778e 100644
--- a/src/direct_bt/L2CAPComm.cpp
+++ b/src/direct_bt/L2CAPComm.cpp
@@ -45,7 +45,7 @@ extern "C" {
#include <poll.h>
}
-#include "dbt_debug.hpp"
+#include <dbt_debug.hpp>
using namespace direct_bt;
diff --git a/src/direct_bt/MgmtComm.cpp b/src/direct_bt/MgmtComm.cpp
index 6c1b9dbc..d4ac14ef 100644
--- a/src/direct_bt/MgmtComm.cpp
+++ b/src/direct_bt/MgmtComm.cpp
@@ -48,7 +48,7 @@ extern "C" {
#include <poll.h>
}
-#include "dbt_debug.hpp"
+#include <dbt_debug.hpp>
using namespace direct_bt;
diff --git a/src/direct_bt/UUID.cpp b/src/direct_bt/UUID.cpp
index 4acfb2e2..83cec826 100644
--- a/src/direct_bt/UUID.cpp
+++ b/src/direct_bt/UUID.cpp
@@ -23,9 +23,9 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dbt_debug.hpp>
#include "UUID.hpp"
-#include "dbt_debug.hpp"
using namespace direct_bt;