diff options
author | Sven Gothel <[email protected]> | 2021-11-09 10:07:23 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2021-11-09 10:07:23 +0100 |
commit | aa76f1b1faa943f3f81b799da47ca38caedfc377 (patch) | |
tree | f98090b663b5e81fc66a2cd751aa69d562933938 /java/org | |
parent | 9e003c83c282e7749b4fcafdca678dc755a307db (diff) |
Slave Peripheral / Gatt Server: Map DBGattServer.hpp types DBGatt[Server|Service|Char|Desc] to Java ; BTAdapter.startAdvertising(..) Adds DBGattServer arg
- Implementation is not yet functional, i.e. types are not yet mapped to native instance.
- DBGattChar and DBGattDesc value currently just a 'byte[]' and lacks capacity:
- Its capacity defines the maximum writable variable length
- and its size defines the maximum writable fixed length.
Diffstat (limited to 'java/org')
-rw-r--r-- | java/org/direct_bt/BTAdapter.java | 11 | ||||
-rw-r--r-- | java/org/direct_bt/BTGattDesc.java | 9 | ||||
-rw-r--r-- | java/org/direct_bt/DBGattChar.java | 183 | ||||
-rw-r--r-- | java/org/direct_bt/DBGattDesc.java | 111 | ||||
-rw-r--r-- | java/org/direct_bt/DBGattServer.java | 143 | ||||
-rw-r--r-- | java/org/direct_bt/DBGattService.java | 74 |
6 files changed, 490 insertions, 41 deletions
diff --git a/java/org/direct_bt/BTAdapter.java b/java/org/direct_bt/BTAdapter.java index 3f1ef2ae..7edaf378 100644 --- a/java/org/direct_bt/BTAdapter.java +++ b/java/org/direct_bt/BTAdapter.java @@ -270,6 +270,8 @@ public interface BTAdapter extends BTObject * * If successful, method also changes [this adapter's role](@ref BTAdapterRoles) to ::BTRole::Slave. * + * @param gattServerData_ the {@link DBGattServer} data to be advertised and offered via GattHandler as ::GATTRole::Server. + * Its handles will be setup via DBGattServer::setServicesHandles(). * @param adv_interval_min in units of 0.625ms, default value 0x0800 for 1.28s; Value range [0x0020 .. 0x4000] for [20ms .. 10.24s] * @param adv_interval_max in units of 0.625ms, default value 0x0800 for 1.28s; Value range [0x0020 .. 0x4000] for [20ms .. 10.24s] * @param adv_type see AD_PDU_Type, default 0x00, i.e. ::AD_PDU_Type::ADV_IND @@ -283,12 +285,15 @@ public interface BTAdapter extends BTObject * @see @ref BTAdapterRoles * @since 2.4.0 */ - HCIStatusCode startAdvertising(final short adv_interval_min, final short adv_interval_max, + HCIStatusCode startAdvertising(final DBGattServer gattServerData, + final short adv_interval_min, final short adv_interval_max, final byte adv_type, final byte adv_chan_map, final byte filter_policy); /** * Starts advertising using all default arguments, see {@link #startAdvertising(short, short, byte, byte, byte)} for details. * + * @param gattServerData_ the {@link DBGattServer} data to be advertised and offered via GattHandler as ::GATTRole::Server. + * Its handles will be setup via DBGattServer::setServicesHandles(). * @return HCIStatusCode::SUCCESS if successful, otherwise the HCIStatusCode error state * @see #startAdvertising(short, short, byte, byte, byte) * @see #stopAdvertising() @@ -297,8 +302,8 @@ public interface BTAdapter extends BTObject * @see @ref BTAdapterRoles * @since 2.4.0 */ - HCIStatusCode startAdvertising(); /* { - return startAdvertising((short)0x0800, (short)0x0800, (byte)0, // AD_PDU_Type::ADV_IND, + HCIStatusCode startAdvertising(final DBGattServer gattServerData); /* { + return startAdvertising(gattServerData, (short)0x0800, (short)0x0800, (byte)0, // AD_PDU_Type::ADV_IND, (byte)0x07, (byte)0x00); } */ diff --git a/java/org/direct_bt/BTGattDesc.java b/java/org/direct_bt/BTGattDesc.java index e3d6fb3b..7b8e5c57 100644 --- a/java/org/direct_bt/BTGattDesc.java +++ b/java/org/direct_bt/BTGattDesc.java @@ -32,6 +32,15 @@ package org.direct_bt; */ public interface BTGattDesc extends BTObject { + public static class UUID128 { + /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.1 Characteristic Extended Properties */ + public static final String EXT_PROP = "00002900-0000-1000-8000-00805f9b34fb"; + /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.2 Characteristic User Description (Characteristic Descriptor, optional, single, string) */ + public static final String USER_DESC = "00002901-0000-1000-8000-00805f9b34fb"; + /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration (Characteristic Descriptor, optional, single, uint16_t bitfield) */ + public static final String CCC_DESC = "00002902-0000-1000-8000-00805f9b34fb"; + } + /** Reads the value of this descriptor * @return A vector<uchar> containing data from this descriptor */ diff --git a/java/org/direct_bt/DBGattChar.java b/java/org/direct_bt/DBGattChar.java index ae3e9458..7e127b8e 100644 --- a/java/org/direct_bt/DBGattChar.java +++ b/java/org/direct_bt/DBGattChar.java @@ -1,7 +1,7 @@ /** * Author: Sven Gothel <[email protected]> - * Copyright (c) 2020 Gothel Software e.K. - * Copyright (c) 2020 ZAFENA AB + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2021 ZAFENA AB * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -25,6 +25,7 @@ package org.direct_bt; +import java.nio.charset.StandardCharsets; import java.util.List; /** @@ -41,39 +42,191 @@ import java.util.List; */ public class DBGattChar { + private final boolean enabledNotifyState = false; + private final boolean enabledIndicateState = false; + + public static class UUID16 { + // + // GENERIC_ACCESS + // + public static String DEVICE_NAME = "2a00"; + public static String APPEARANCE = "2a01"; + public static String PERIPHERAL_PRIVACY_FLAG = "2a02"; + public static String RECONNECTION_ADDRESS = "2a03"; + public static String PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS = "2a04"; + + // + // DEVICE_INFORMATION + // + /** Mandatory: uint40 */ + public static String SYSTEM_ID = "2a23"; + public static String MODEL_NUMBER_STRING = "2a24"; + public static String SERIAL_NUMBER_STRING = "2a25"; + public static String FIRMWARE_REVISION_STRING = "2a26"; + public static String HARDWARE_REVISION_STRING = "2a27"; + public static String SOFTWARE_REVISION_STRING = "2a28"; + public static String MANUFACTURER_NAME_STRING = "2a29"; + public static String REGULATORY_CERT_DATA_LIST = "2a2a"; + public static String PNP_ID = "2a50"; + } + /** * Characteristic Handle of this instance. * <p> * Attribute handles are unique for each device (server) (BT Core Spec v5.2: Vol 3, Part F Protocol..: 3.2.2 Attribute Handle). * </p> */ - public native short getHandle(); + public short handle; /** - * Characteristics Value Handle. + * Characteristic end handle, inclusive. * <p> * Attribute handles are unique for each device (server) (BT Core Spec v5.2: Vol 3, Part F Protocol..: 3.2.2 Attribute Handle). * </p> */ - public native short getValueHandle(); - - /* Characteristics Value Type UUID */ - public native String getValueUUID(); + public short end_handle; /** - * Returns the properties of this characteristic. + * Characteristics Value Handle. * <p> - * BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.1.1 Characteristic Properties + * Attribute handles are unique for each device (server) (BT Core Spec v5.2: Vol 3, Part F Protocol..: 3.2.2 Attribute Handle). * </p> */ - public native GattCharPropertySet getProperties(); + public short value_handle; + + /* Characteristics Value Type UUID (lower-case)*/ + public String value_type; + + /* Characteristics Property */ + GattCharPropertySet properties; /** List of Characteristic Descriptions. */ - public native List<DBGattDesc> getDescriptors(); + public List<DBGattDesc> descriptors; - /* Characteristics's Value */ - public native byte[] getValue(); + /** + * Characteristics's Value. + * + * Its capacity defines the maximum writable variable length + * and its size defines the maximum writable fixed length. + * + * FIXME: Needs capacity and length (or size) + */ + public byte[] value; + + /** + * True if value is of variable length, otherwise fixed length. + */ + public boolean variable_length; + + /* Optional Client Characteristic Configuration index within descriptorList */ + public int clientCharConfigIndex; + + /* Optional Characteristic User Description index within descriptorList */ + public int userDescriptionIndex; + + private void setup(final String value_type_, + final GattCharPropertySet properties_, + final List<DBGattDesc> descriptors_, + final byte[] value_, final boolean variable_length_) + { + handle = 0; + end_handle = 0; + value_handle = 0; + value_type = value_type_; + properties = properties_; + descriptors = descriptors_; + value = value_; + variable_length = variable_length_; + clientCharConfigIndex = -1; + userDescriptionIndex = -1; + + int i=0; + for(final DBGattDesc d : descriptors) { + if( 0 > clientCharConfigIndex && d.isClientCharConfig() ) { + clientCharConfigIndex=i; + } else if( 0 > userDescriptionIndex && d.isUserDescription() ) { + userDescriptionIndex=i; + } + ++i; + } + } + + public DBGattChar(final String value_type_, + final GattCharPropertySet properties_, + final List<DBGattDesc> descriptors_, + final byte[] value_, final boolean variable_length_) + { + setup(value_type_, properties_, descriptors_, value_, variable_length_); + } + + public DBGattChar(final String value_type_, + final GattCharPropertySet properties_, + final List<DBGattDesc> descriptors_, + final byte[] value_) + { + setup(value_type_, properties_, descriptors_, value_, true /* variable_length_ */); + } + + public boolean hasProperties(final GattCharPropertySet.Type bit) { + return properties.isSet(bit); + } + + /** Fill value with zero bytes. */ + public void bzero() { + for(int i=0; i<value.length; i++) { // anything more efficient? + value[i]=0; + } + } + + public DBGattDesc getClientCharConfig() { + if( 0 > clientCharConfigIndex ) { + return null; + } + return descriptors.get(clientCharConfigIndex); // abort if out of bounds + } + + public DBGattDesc getUserDescription() { + if( 0 > userDescriptionIndex ) { + return null; + } + return descriptors.get(userDescriptionIndex); // abort if out of bounds + } @Override - public native String toString(); + public boolean equals(final Object other) { + if( this == other ) { + return true; + } + if( !(other instanceof DBGattChar) ) { + return false; + } + final DBGattChar o = (DBGattChar)other; + return handle == o.handle; /** unique attribute handles */ + } + + @Override + public String toString() { + final String char_name; + final String notify_str; + { + final DBGattDesc ud = getUserDescription(); + if( null != ud ) { + char_name = ", '" + new String(ud.value, StandardCharsets.UTF_8) + "'"; + } else { + char_name = ""; + } + } + if( hasProperties(GattCharPropertySet.Type.Notify) || hasProperties(GattCharPropertySet.Type.Indicate) ) { + notify_str = ", enabled[notify "+enabledNotifyState+", indicate "+enabledIndicateState+"]"; + } else { + notify_str = ""; + } + final String len = variable_length ? "var" : "fixed"; + return "Char[handle [0x"+Integer.toHexString(handle)+"..0x"+Integer.toHexString(end_handle)+ + "], props 0x"+Integer.toHexString(properties.mask)+" "+properties.toString()+ + char_name+", value[type 0x"+value_type+", handle 0x"+Integer.toHexString(value_handle)+", len "+len+ + ", "+BTUtils.bytesHexString(value, 0, value.length, true /* lsbFirst */)+ + "], ccd-idx "+clientCharConfigIndex+notify_str+"]"; + } + } diff --git a/java/org/direct_bt/DBGattDesc.java b/java/org/direct_bt/DBGattDesc.java index cb826963..18217382 100644 --- a/java/org/direct_bt/DBGattDesc.java +++ b/java/org/direct_bt/DBGattDesc.java @@ -1,7 +1,7 @@ /** * Author: Sven Gothel <[email protected]> - * Copyright (c) 2020 Gothel Software e.K. - * Copyright (c) 2020 ZAFENA AB + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2021 ZAFENA AB * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -34,27 +34,118 @@ package org.direct_bt; */ public class DBGattDesc { + public static class UUID16 { + /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.1 Characteristic Extended Properties */ + public static final String EXT_PROP = "2900"; + /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.2 Characteristic User Description (Characteristic Descriptor, optional, single, string) */ + public static final String USER_DESC = "2901"; + /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration (Characteristic Descriptor, optional, single, uint16_t bitfield) */ + public static final String CCC_DESC = "2902"; + } + /** * Characteristic Descriptor Handle * <p> * Attribute handles are unique for each device (server) (BT Core Spec v5.2: Vol 3, Part F Protocol..: 3.2.2 Attribute Handle). * </p> */ - public native short getHandle(); + public short handle; + + /** Type of descriptor UUID (lower-case) */ + public String type; + + /** + * Characteristic Descriptor's Value. + * + * Its capacity defines the maximum writable variable length + * and its size defines the maximum writable fixed length. + * + * FIXME: Needs capacity and length (or size) + */ + public byte[] value; + + /** + * True if value is of variable length, otherwise fixed length. + */ + public boolean variable_length; + + private void setup(final String type_, + final byte[] value_, final boolean variable_length_) + { + handle = 0; + type = type_; + value = value_; + variable_length = variable_length_; + + if( variable_length && ( isExtendedProperties() || isClientCharConfig() ) ) { + variable_length = false; + } + } + + /** + * + * @param type_ + * @param value_ + * @param variable_length_ defaults to true, but forced to false if isExtendedProperties() or isClientCharConfig(). + */ + public DBGattDesc(final String type_, final byte[] value_, final boolean variable_length_) + { + setup(type_, value_, variable_length_); + } + + /** + * + * @param type_ + * @param value_ + * @param variable_length_ defaults to true, but forced to false if isExtendedProperties() or isClientCharConfig(). + */ + public DBGattDesc(final String type_, final byte[] value_) + { + setup(type_, value_, true /* variable_length_ */); + } - /** Type of descriptor */ - public native String getUUID(); + /** Fill value with zero bytes. */ + public void bzero() { + for(int i=0; i<value.length; i++) { // anything more efficient? + value[i]=0; + } + } - /* Characteristics Descriptor's Value */ - public native byte[] getValue(); + /** + * Return a newly constructed Client Characteristic Configuration + * with a zero uint16_t value of fixed length. + * @see isClientCharConfig() + */ + public static DBGattDesc createClientCharConfig() { + final byte[] p = { (byte)0, (byte)0 }; + return new DBGattDesc( UUID16.CCC_DESC, p, false /* variable_length */ ); + } @Override - public native String toString(); + public String toString() { + final String len = variable_length ? "var" : "fixed"; + return "Desc[type 0x"+type+", handle 0x"+Integer.toHexString(handle)+ + ", value[len "+len+", "+BTUtils.bytesHexString(value, 0, value.length, true /* lsbFirst */)+"]]"; + } /** Value is uint16_t bitfield */ - // public boolean isExtendedProperties() { return BTGattDesc::TYPE_EXT_PROP == getUUID(); } + public boolean isExtendedProperties() { return UUID16.EXT_PROP.equals(type); } /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration (Characteristic Descriptor, optional, single, uint16_t bitfield) */ - // public boolean isClientCharConfig() { return BTGattDesc::TYPE_CCC_DESC == getUUID(); } + public boolean isClientCharConfig() { return UUID16.CCC_DESC.equals(type); } + /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.2 Characteristic User Description */ + public boolean isUserDescription() { return UUID16.USER_DESC.equals(type); } + + @Override + public boolean equals(final Object other) { + if( this == other ) { + return true; + } + if( !(other instanceof DBGattDesc) ) { + return false; + } + final DBGattDesc o = (DBGattDesc)other; + return handle == o.handle; /** unique attribute handles */ + } } diff --git a/java/org/direct_bt/DBGattServer.java b/java/org/direct_bt/DBGattServer.java index 92db25c5..465fef63 100644 --- a/java/org/direct_bt/DBGattServer.java +++ b/java/org/direct_bt/DBGattServer.java @@ -1,7 +1,7 @@ /** * Author: Sven Gothel <[email protected]> - * Copyright (c) 2020 Gothel Software e.K. - * Copyright (c) 2020 ZAFENA AB + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2021 ZAFENA AB * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -39,19 +39,126 @@ import java.util.List; */ public class DBGattServer { + /** + * Listener to remote master device's operations on the local GATT-Server. + * + * All methods shall return as soon as possible to not block GATT event processing. + */ + public static abstract class Listener { + @SuppressWarnings("unused") + private volatile long nativeInstance; + + /** + * Notification that device got connected. + * + * Convenient user entry, allowing to setup resources. + * + * @param device the connected device + * @param initialMTU initial used minimum MTU until negotiated. + */ + abstract void connected(BTDevice device, final int initialMTU); + + /** + * Notification that device got disconnected. + * + * Convenient user entry, allowing to clean up resources. + * + * @param device the disconnected device. + */ + abstract void disconnected(BTDevice device); + + /** + * Notification that the MTU has changed. + * + * @param device the device for which the MTU has changed + * @param mtu the new negotiated MTU + */ + abstract void mtuChanged(BTDevice device, final int mtu); + + /** + * + * @param device + * @param s + * @param c + * @return true if master read has been accepted by GATT-Server listener, otherwise false. Only if all listener return true, the read action will be allowed. + */ + abstract boolean readCharValue(BTDevice device, DBGattService s, DBGattChar c); + + /** + * + * @param device + * @param s + * @param c + * @param d + * @return true if master read has been accepted by GATT-Server listener, otherwise false. Only if all listener return true, the read action will be allowed. + */ + abstract boolean readDescValue(BTDevice device, DBGattService s, DBGattChar c, DBGattDesc d); + + /** + * + * @param device + * @param s + * @param c + * @param value + * @param value_offset + * @return true if master write has been accepted by GATT-Server listener, otherwise false. Only if all listener return true, the write action will be allowed. + */ + abstract boolean writeCharValue(BTDevice device, DBGattService s, DBGattChar c, final byte[] value, final int value_offset); + + /** + * + * @param device + * @param s + * @param c + * @param d + * @param value + * @param value_offset + * @return true if master write has been accepted by GATT-Server listener, otherwise false. Only if all listener return true, the write action will be allowed. + */ + abstract boolean writeDescValue(final BTDevice device, DBGattService s, DBGattChar c, DBGattDesc d, + final byte[] value, final int value_offset); + + /** + * + * @param device + * @param s + * @param c + * @param d + * @param notificationEnabled + * @param indicationEnabled + */ + abstract void clientCharConfigChanged(final BTDevice device, DBGattService s, DBGattChar c, DBGattDesc d, + final boolean notificationEnabled, final boolean indicationEnabled); + + /** + * Default comparison operator, merely testing for same memory reference. + * <p> + * Specializations may override. + * </p> + */ + @Override + public boolean equals(final Object other) { + return this == other; + } + } + // private final List<Listener> listenerList = new ArrayList<Listener>(); + /** Used maximum server Rx ATT_MTU */ public int max_att_mtu = 512 + 1; // BTGattHandler::Defaults::MAX_ATT_MTU; /** List of Services. */ public List<DBGattService> services; + public DBGattServer() { + services = new ArrayList<DBGattService>(); + } public DBGattServer(final List<DBGattService> services_) { services = services_; } public DBGattService findGattService(final String service_uuid) { for(final DBGattService s : services) { - if( service_uuid.equals(s.getUUID()) ) { + if( service_uuid.equals( s.type ) ) { return s; } } @@ -66,4 +173,34 @@ public class DBGattServer return service.findGattChar(char_uuid); } + public synchronized boolean addListener(final Listener l) { + return addListenerImpl(l); + } + private native boolean addListenerImpl(Listener l); + + public synchronized boolean removeListener(final Listener l) { + return removeListenerImpl(l); + } + private native boolean removeListenerImpl(Listener l); + + public String toFullString() { + final String newline = System.lineSeparator(); + final StringBuilder res = new StringBuilder(toString()+newline); + for(final DBGattService s : services) { + res.append(" ").append(s.toString()).append(newline); + for(final DBGattChar c : s.characteristics) { + res.append(" ").append(c.toString()).append(newline); + for(final DBGattDesc d : c.descriptors) { + res.append(" ").append(d.toString()).append(newline); + } + } + } + return res.toString(); + } + + @Override + public String toString() { + return "DBSrv[max mtu "+max_att_mtu+", "+services.size()+" services]"; + + } } diff --git a/java/org/direct_bt/DBGattService.java b/java/org/direct_bt/DBGattService.java index 5817317a..fcc74a51 100644 --- a/java/org/direct_bt/DBGattService.java +++ b/java/org/direct_bt/DBGattService.java @@ -1,7 +1,7 @@ /** * Author: Sven Gothel <[email protected]> - * Copyright (c) 2020 Gothel Software e.K. - * Copyright (c) 2020 ZAFENA AB + * Copyright (c) 2021 Gothel Software e.K. + * Copyright (c) 2021 ZAFENA AB * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -40,10 +40,26 @@ import java.util.List; */ public class DBGattService { + public static class UUID16 { + /** This service contains generic information about the device. This is a mandatory service. */ + public static String GENERIC_ACCESS = "1800"; + /** The service allows receiving indications of changed services. This is a mandatory service. */ + public static String GENERIC_ATTRIBUTE = "1801"; + /** This service exposes a control point to change the peripheral alert behavior. */ + public static String IMMEDIATE_ALERT = "1802"; + /** The service defines behavior on the device when a link is lost between two devices. */ + public static String LINK_LOSS = "1803"; + /** This service exposes temperature and other data from a thermometer intended for healthcare and fitness applications. */ + public static String HEALTH_THERMOMETER = "1809"; + /** This service exposes manufacturer and/or vendor information about a device. */ + public static String DEVICE_INFORMATION = "180A"; + /** This service exposes the state of a battery within a device. */ + public static String BATTERY_SERVICE = "180F"; + }; /** * Indicate whether this service is a primary service. */ - public native boolean isPrimary(); + public boolean primary; /** * Service start handle @@ -51,7 +67,7 @@ public class DBGattService * Attribute handles are unique for each device (server) (BT Core Spec v5.2: Vol 3, Part F Protocol..: 3.2.2 Attribute Handle). * </p> */ - public native short getHandle(); + public short handle; /** * Service end handle, inclusive. @@ -59,20 +75,58 @@ public class DBGattService * Attribute handles are unique for each device (server) (BT Core Spec v5.2: Vol 3, Part F Protocol..: 3.2.2 Attribute Handle). * </p> */ - public native short getEndHandle(); + public short end_handle; - /** Service type UUID */ - public native String getUUID(); + /** Service type UUID (lower-case) */ + public String type; /** List of Characteristic Declarations. */ - public native List<DBGattChar> getChars(); + List<DBGattChar> characteristics; + + public DBGattService(final boolean primary_, + final String type_, + final List<DBGattChar> characteristics_) + { + primary = primary_; + handle = 0; + end_handle = 0; + type = type_; + characteristics = characteristics_; + } public DBGattChar findGattChar(final String char_uuid) { - for(final DBGattChar c : getChars()) { - if( char_uuid.equals(c.getValueUUID()) ) { + for(final DBGattChar c : characteristics) { + if( char_uuid.equals( c.value_type ) ) { + return c; + } + } + return null; + } + public DBGattChar findGattCharByValueHandle(final short char_value_handle) { + for(final DBGattChar c : characteristics) { + if( char_value_handle == c.value_handle ) { return c; } } return null; } + + @Override + public boolean equals(final Object other) { + if( this == other ) { + return true; + } + if( !(other instanceof DBGattService) ) { + return false; + } + final DBGattService o = (DBGattService)other; + return handle == o.handle && end_handle == o.end_handle; /** unique attribute handles */ + } + + @Override + public String toString() { + return "Srvc[type 0x"+type+", handle [0x"+Integer.toHexString(handle)+"..0x"+Integer.toHexString(end_handle)+"], "+ + characteristics.size()+" chars]"; + + } } |