diff options
author | Sven Gothel <[email protected]> | 2020-05-17 09:58:12 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-05-17 09:58:12 +0200 |
commit | a0efba06113ada15db4a88cd4fd641e30f121e67 (patch) | |
tree | 8285387267a94bfb340548e816ab95db4f8dbf0e | |
parent | c60e97e43c8826d3aeef46c65babef03eaefced6 (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.hpp | 85 | ||||
-rw-r--r-- | src/direct_bt/GATTTypes.cpp | 150 |
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; -} |