diff options
Diffstat (limited to 'java/jni')
-rw-r--r-- | java/jni/BluetoothUtils.cxx (renamed from java/jni/HCIGattDescriptor.cxx) | 29 | ||||
-rw-r--r-- | java/jni/CMakeLists.txt | 38 | ||||
-rw-r--r-- | java/jni/HCIManager.cxx | 30 | ||||
-rw-r--r-- | java/jni/HCIObject.cxx | 34 | ||||
-rw-r--r-- | java/jni/JNIMem.cxx | 31 | ||||
-rw-r--r-- | java/jni/JNIMem.hpp | 28 | ||||
-rw-r--r-- | java/jni/direct_bt/CMakeLists.txt | 53 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTAdapter.cxx | 259 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTDevice.cxx | 78 | ||||
-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/HCIDevice.cxx) | 6 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTGattService.cxx (renamed from java/jni/HCIGattService.cxx) | 6 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTManager.cxx | 106 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTNativeDownlink.cxx | 58 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTObject.cxx (renamed from java/jni/HCIAdapter.cxx) | 6 | ||||
-rw-r--r-- | java/jni/direct_bt/helper_dbt.cxx | 65 | ||||
-rw-r--r-- | java/jni/direct_bt/helper_dbt.hpp | 113 | ||||
-rw-r--r-- | java/jni/helper_base.cxx | 27 | ||||
-rw-r--r-- | java/jni/helper_base.hpp | 68 | ||||
-rw-r--r-- | java/jni/tinyb/CMakeLists.txt | 54 | ||||
-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 |
31 files changed, 1000 insertions, 163 deletions
diff --git a/java/jni/HCIGattDescriptor.cxx b/java/jni/BluetoothUtils.cxx index cefc6b4d..83e71dd0 100644 --- a/java/jni/HCIGattDescriptor.cxx +++ b/java/jni/BluetoothUtils.cxx @@ -23,12 +23,31 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "direct_bt/HCITypes.hpp" +#include "org_tinyb_BluetoothUtils.h" -#include "tinyb_hci_HCIGattDescriptor.h" +#include <cstdint> +#include <cinttypes> -#include "JNIMem.hpp" -#include "helper_base.hpp" +#include <time.h> -using namespace direct_bt; +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/HCIDevice.cxx b/java/jni/direct_bt/DBTGattDescriptor.cxx index d143b85d..59410d92 100644 --- a/java/jni/HCIDevice.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_HCIDevice.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/HCIGattService.cxx b/java/jni/direct_bt/DBTGattService.cxx index 14dfcbe8..6e0fe141 100644 --- a/java/jni/HCIGattService.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_HCIGattService.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/HCIAdapter.cxx b/java/jni/direct_bt/DBTObject.cxx index afb420fc..74f40e8a 100644 --- a/java/jni/HCIAdapter.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_HCIAdapter.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 |