aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-05-17 09:58:12 +0200
committerSven Gothel <[email protected]>2020-05-17 09:58:12 +0200
commita0efba06113ada15db4a88cd4fd641e30f121e67 (patch)
tree8285387267a94bfb340548e816ab95db4f8dbf0e
parentc60e97e43c8826d3aeef46c65babef03eaefced6 (diff)
Working GATT Java Side; GATT Types made fully functional for user to avoid 'technical' GATTHandler
GATT Types made fully functional for user to avoid 'technical' GATTHandler (C++) > GATTService, GATTCharacteristic, GATTDescriptor -- Reside in their own respective files -- Added semantic methods (readValue(), ..) implemented using DBTDevice -> GATTHandler -- GATTDescriptor owns its value -- GATTHandler setSendIndicationConfirmation(..) defaults to true -- Allow user to cirvumvent using GATTHandler manually completely, device 1--*> services 1--*> characteristics 1--*> descriptor -- C++ GATT types aligned 1:1 to TinyB (Java) > Merged GATTIndicationListener + GATTNotificationListener -> GATTCharacteristicListener -- Simplifying usage, unifying notification and indication -- Now using a list of shared_ptr<GATTCharacteristicListener> allowing multiple actors instead of just a one shot entry. Similar to AdapterStatusListener, we utilize this also on the Java side to implement the TinyB notifications. See dbt_scanner00.cpp: Simplified high-level usage. See dbt_scanner01.cpp: Lower-level technical usage w/ GATTHandler. +++ > Simplified more names > Removed redundancy in listener callbacks, -- don't pass adapter when device is already given. device <*--1> adapter -- don't pass GATT handle explicitly when characteristic is passed > Comparison of all GATT types are done by their respective unique handle Attribute handles are unique for each device (server) (BT Core Spec v5.2: Vol 3, Part F Protocol..: 3.2.2 Attribute Handle) > GATTHandler: Own L2CAPComm instance directly, instead of shared_ptr. > JNIMem: Added JNICriticalArray class for RAII style release ++++ ++++ Working GATT Java Side > All toString() methods return the C++ toString() via JNI for better representation. > DBTDevice.java/JNI: Resolved the odd 'adapter' reference issue: -- Was not passing the jobject of DBTAdapter, but its shared container refeference ;-) > All GATT types receive their GATT handler for equal test and identity @ ctor > GATT read/write Value update the cached value as well as issue the notifyValue on change, including GATTCharacteristic notification/indication listener
-rw-r--r--java/jni/JNIMem.hpp85
-rw-r--r--src/direct_bt/GATTTypes.cpp150
2 files changed, 83 insertions, 152 deletions
diff --git a/java/jni/JNIMem.hpp b/java/jni/JNIMem.hpp
index fee3348..a6a1dbb 100644
--- a/java/jni/JNIMem.hpp
+++ b/java/jni/JNIMem.hpp
@@ -67,8 +67,10 @@ public:
extern thread_local JNIEnvContainer jni_env;
/*
- * This class provides a lifetime-managed GlobalRef variable, which is automatically
- * deleted when it goes out of scope.
+ * This class provides a lifetime-managed GlobalRef variable,
+ * which is automatically deleted when it goes out of scope.
+ *
+ * RAII-style acquire and relinquish via destructor
*/
class JNIGlobalRef {
private:
@@ -110,5 +112,84 @@ public:
{ return !( *this == rhs ); }
};
+/*
+ * This class provides a lifetime-managed 'PrimitiveArrayCritical' pinned heap,
+ * which is automatically released when it goes out of scope.
+ *
+ * RAII-style acquire and relinquish via destructor
+ */
+template <typename T>
+class JNICriticalArray {
+public:
+ enum Mode : jint {
+ /** Like default 0: If 'isCopy': Update the java array data with the copy and free the copy. */
+ UPDATE_AND_RELEASE = 0,
+
+ /** Like JNI_COMMIT: If 'isCopy': Update the java array data with the copy, but do not free the copy. */
+ UPDATE_NO_RELEASE = JNI_COMMIT,
+
+ /** Like default JNI_ABORT: If 'isCopy': Do not update the java array data with the copy, but free the copy. */
+ NO_UPDATE_AND_RELEASE = JNI_ABORT,
+ };
+
+private:
+ JNIEnv *env;
+ Mode mode = UPDATE_AND_RELEASE;
+ jbyteArray jarray = nullptr;
+ T* narray = nullptr;
+ jboolean isCopy = false;
+
+public:
+ JNICriticalArray(JNIEnv *env) : env(env) {}
+
+ JNICriticalArray(const JNICriticalArray &o) = delete;
+ JNICriticalArray(JNICriticalArray &&o) = delete;
+ JNICriticalArray& operator=(const JNICriticalArray &o) = delete;
+ JNICriticalArray& operator=(JNICriticalArray &&o) = delete;
+
+ /**
+ * Release the acquired primitive array, RAII style.
+ */
+ ~JNICriticalArray() {
+ release();
+ }
+
+ /**
+ * Manual release of the acquired primitive array,
+ * usually one likes to simply do this via the destructor, RAII style.
+ */
+ void release() {
+ if( nullptr != narray ) {
+ env->ReleasePrimitiveArrayCritical(jarray, narray, mode);
+ this->jarray = nullptr;
+ this->narray = nullptr;
+ this->env = nullptr;
+ }
+ }
+
+ /**
+ * Acquired the primitive array.
+ */
+ T* get(jbyteArray jarray, Mode mode=UPDATE_AND_RELEASE) {
+ if( nullptr == jarray ) {
+ return nullptr;
+ }
+ T* narray = static_cast<T*>( env->GetPrimitiveArrayCritical(jarray, &isCopy) );
+ if( nullptr != narray ) {
+ this->mode = mode;
+ this->jarray = jarray;
+ this->narray = narray;
+ return narray;
+ }
+ return nullptr;
+ }
+
+ /**
+ * Returns true if the primitive array had been acquired
+ * and the JVM utilizes a copy of the underlying java array.
+ */
+ bool getIsCopy() const { return isCopy; }
+};
+
#endif /* JNIMEM__HPP_ */
diff --git a/src/direct_bt/GATTTypes.cpp b/src/direct_bt/GATTTypes.cpp
deleted file mode 100644
index 70e3f59..0000000
--- a/src/direct_bt/GATTTypes.cpp
+++ /dev/null
@@ -1,150 +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 <dbt_debug.hpp>
-#include <cstring>
-#include <string>
-#include <memory>
-#include <cstdint>
-#include <vector>
-#include <cstdio>
-
-#include <algorithm>
-
-#include "GATTTypes.hpp"
-
-
-using namespace direct_bt;
-
-const uuid16_t GATTDescriptor::TYPE_EXT_PROP(Type::CHARACTERISTIC_EXTENDED_PROPERTIES);
-const uuid16_t GATTDescriptor::TYPE_USER_DESC(Type::CHARACTERISTIC_USER_DESCRIPTION);
-const uuid16_t GATTDescriptor::TYPE_CCC_DESC(Type::CLIENT_CHARACTERISTIC_CONFIGURATION);
-
-#define CHAR_DECL_PROPS_ENUM(X) \
- X(Broadcast,broadcast) \
- X(Read,read) \
- X(WriteNoAck,write-without-response) \
- X(WriteWithAck,write) \
- X(Notify,notify) \
- X(Indicate,indicate) \
- X(AuthSignedWrite,authenticated-signed-writes) \
- X(ExtProps,extended-properties)
-
-/**
- "reliable-write"
- "writable-auxiliaries"
- "encrypt-read"
- "encrypt-write"
- "encrypt-authenticated-read"
- "encrypt-authenticated-write"
- "secure-read" (Server only)
- "secure-write" (Server only)
- "authorize"
- */
-
-#define CASE_TO_STRING2(V,S) case V: return #S;
-
-std::string GATTCharacteristic::getPropertyString(const PropertyBitVal prop) {
- switch(prop) {
- CHAR_DECL_PROPS_ENUM(CASE_TO_STRING2)
- default: ; // fall through intended
- }
- return "Unknown property";
-}
-
-std::string GATTCharacteristic::getPropertiesString(const PropertyBitVal properties) {
- const PropertyBitVal none = static_cast<PropertyBitVal>(0);
- const uint8_t one = 1;
- bool has_pre = false;
- std::string out("[");
- for(int i=0; i<8; i++) {
- const PropertyBitVal propertyBit = static_cast<PropertyBitVal>( one << i );
- if( none != ( properties & propertyBit ) ) {
- if( has_pre ) { out.append(", "); }
- out.append(getPropertyString(propertyBit));
- has_pre = true;
- }
- }
- out.append("]");
- return out;
-}
-
-std::vector<std::unique_ptr<std::string>> GATTCharacteristic::getPropertiesStringList(const PropertyBitVal properties) {
- std::vector<std::unique_ptr<std::string>> out;
- const PropertyBitVal none = static_cast<PropertyBitVal>(0);
- const uint8_t one = 1;
- for(int i=0; i<8; i++) {
- const PropertyBitVal propertyBit = static_cast<PropertyBitVal>( one << i );
- if( none != ( properties & propertyBit ) ) {
- out.push_back( std::unique_ptr<std::string>( new std::string( getPropertyString(propertyBit) ) ) );
- }
- }
- return out;
-}
-
-std::string GATTCharacteristic::toString() const {
- const std::shared_ptr<const uuid_t> & service_uuid = service->type;
- const uint16_t service_handle_end = service->endHandle;
- std::string service_name = "";
- std::string char_name = "";
- std::string desc_str = ", descr[ ";
- if( uuid_t::UUID16_SZ == service_uuid->getTypeSize() ) {
- const uint16_t uuid16 = (static_cast<const uuid16_t*>(service_uuid.get()))->value;
- service_name = ", "+GattServiceTypeToString(static_cast<GattServiceType>(uuid16));
- }
- if( uuid_t::UUID16_SZ == value_type->getTypeSize() ) {
- const uint16_t uuid16 = (static_cast<const uuid16_t*>(value_type.get()))->value;
- char_name = ", "+GattCharacteristicTypeToString(static_cast<GattCharacteristicType>(uuid16));
- }
- for(size_t i=0; i<descriptorList.size(); i++) {
- const GATTDescriptorRef cd = descriptorList[i];
- desc_str += cd->toString() + ", ";
- }
- desc_str += " ]";
- return "handle "+uint16HexString(handle)+", props "+uint8HexString(properties)+" "+getPropertiesString()+
- ", value[type 0x"+value_type->toString()+", handle "+uint16HexString(value_handle)+char_name+desc_str+
- "], service[type 0x"+service_uuid->toString()+
- ", handle[ "+uint16HexString(service_handle)+".."+uint16HexString(service_handle_end)+" ]"+
- service_name+" ]";
-}
-
-std::string GATTService::toString() const {
- std::string name = "";
- if( uuid_t::UUID16_SZ == type->getTypeSize() ) {
- const uint16_t uuid16 = (static_cast<const uuid16_t*>(type.get()))->value;
- name = " - "+GattServiceTypeToString(static_cast<GattServiceType>(uuid16));
- }
- std::string res = "type 0x"+type->toString()+", handle ["+uint16HexString(startHandle, true)+".."+uint16HexString(endHandle, true)+"]"+
- name+"[ ";
-
- for(size_t i=0; i<characteristicList.size(); i++) {
- if( 0 < i ) {
- res += ", ";
- }
- res += std::to_string(i)+"[ "+characteristicList[i]->toString()+" ]";
- }
- res += " ]";
- return res;
-}