aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2021-09-24 13:30:43 +0200
committerSven Gothel <[email protected]>2021-09-24 13:30:43 +0200
commit8b475db0e662e00a1577b7a6090c3a99857560c8 (patch)
tree87bb68c109b892a6ab118614004268da005246b3 /java
parent61bfb0757a1c337eaf86f9df8b0524bec1b7bc0f (diff)
Java: BTAdapter/BTDevice: Add [get|set]ConnectedLE_PHY(..), setDefaultLE_PHY(); Add LE_Features and LE_PHYs class
Supporting added LE_PHYs features of commit 61bfb0757a1c337eaf86f9df8b0524bec1b7bc0f in Java
Diffstat (limited to 'java')
-rw-r--r--java/jau/direct_bt/DBTAdapter.java21
-rw-r--r--java/jau/direct_bt/DBTDevice.java37
-rw-r--r--java/jni/direct_bt/DBTAdapter.cxx28
-rw-r--r--java/jni/direct_bt/DBTDevice.cxx84
-rw-r--r--java/org/direct_bt/BTAdapter.java27
-rw-r--r--java/org/direct_bt/BTDevice.java62
-rw-r--r--java/org/direct_bt/LE_Features.java119
-rw-r--r--java/org/direct_bt/LE_PHYs.java85
8 files changed, 459 insertions, 4 deletions
diff --git a/java/jau/direct_bt/DBTAdapter.java b/java/jau/direct_bt/DBTAdapter.java
index 15eb4ed9..88ca12f0 100644
--- a/java/jau/direct_bt/DBTAdapter.java
+++ b/java/jau/direct_bt/DBTAdapter.java
@@ -52,6 +52,8 @@ import org.direct_bt.BTUtils;
import org.direct_bt.EIRDataTypeSet;
import org.direct_bt.HCIStatusCode;
import org.direct_bt.HCIWhitelistConnectType;
+import org.direct_bt.LE_Features;
+import org.direct_bt.LE_PHYs;
import org.direct_bt.PairingMode;
import org.direct_bt.SMPPairingState;
import org.direct_bt.ScanType;
@@ -299,6 +301,13 @@ public class DBTAdapter extends DBTObject implements BTAdapter
private native byte resetImpl();
@Override
+ public final HCIStatusCode setDefaultLE_PHY(final boolean tryTx, final boolean tryRx, final LE_PHYs Tx, final LE_PHYs Rx) {
+ return HCIStatusCode.get( setDefaultLE_PHYImpl(tryTx, tryRx, Tx.mask, Rx.mask) );
+ }
+ private native byte setDefaultLE_PHYImpl(final boolean tryTx, final boolean tryRx,
+ final byte Tx, final byte Rx);
+
+ @Override
public native boolean setDiscoverable(boolean value);
@Override
@@ -315,15 +324,21 @@ public class DBTAdapter extends DBTObject implements BTAdapter
@Override
public final boolean isPowered() { return isValid() && isPoweredImpl(); }
- public native boolean isPoweredImpl();
+ private native boolean isPoweredImpl();
@Override
public final boolean isSuspended() { return isValid() && isSuspendedImpl(); }
- public native boolean isSuspendedImpl();
+ private native boolean isSuspendedImpl();
@Override
public final boolean isValid() { return super.isValid() && isValidImpl(); }
- public native boolean isValidImpl();
+ private native boolean isValidImpl();
+
+ @Override
+ public final LE_Features getLEFeatures() {
+ return new LE_Features( getLEFeaturesImpl() );
+ }
+ private native long getLEFeaturesImpl();
/* internal */
diff --git a/java/jau/direct_bt/DBTDevice.java b/java/jau/direct_bt/DBTDevice.java
index e7b9c36f..4ad2aa2b 100644
--- a/java/jau/direct_bt/DBTDevice.java
+++ b/java/jau/direct_bt/DBTDevice.java
@@ -47,6 +47,7 @@ import org.direct_bt.BTUtils;
import org.direct_bt.EIRDataTypeSet;
import org.direct_bt.BTGattCharListener;
import org.direct_bt.HCIStatusCode;
+import org.direct_bt.LE_PHYs;
import org.direct_bt.PairingMode;
import org.direct_bt.SMPIOCapability;
import org.direct_bt.SMPKeyMask;
@@ -224,6 +225,40 @@ public class DBTDevice extends DBTObject implements BTDevice
public final short getConnectionHandle() { return hciConnHandle; }
@Override
+ public HCIStatusCode getConnectedLE_PHY(final LE_PHYs[] resTx, final LE_PHYs[] resRx) {
+ // pre-init
+ resTx[0] = new LE_PHYs(LE_PHYs.PHY.LE_1M);
+ resRx[0] = new LE_PHYs(LE_PHYs.PHY.LE_1M);
+ final byte[] t = { resTx[0].mask };
+ final byte[] r = { resRx[0].mask };
+ final HCIStatusCode res = HCIStatusCode.get( getConnectedLE_PHYImpl(t, r) );
+ resTx[0] = new LE_PHYs(t[0]);
+ resRx[0] = new LE_PHYs(r[0]);
+ return res;
+ }
+ private native byte getConnectedLE_PHYImpl(byte[] resTx, byte[] resRx);
+
+ @Override
+ public HCIStatusCode setConnectedLE_PHY(final boolean tryTx, final boolean tryRx,
+ final LE_PHYs Tx, final LE_PHYs Rx) {
+ return HCIStatusCode.get( setConnectedLE_PHYImpl(tryTx, tryRx, Tx.mask, Rx.mask) );
+ }
+ private native byte setConnectedLE_PHYImpl(final boolean tryTx, final boolean tryRx,
+ final byte Tx, final byte Rx);
+
+ @Override
+ public final LE_PHYs getTxPhys() {
+ return new LE_PHYs( getTxPhysImpl() );
+ }
+ private native byte getTxPhysImpl();
+
+ @Override
+ public final LE_PHYs getRxPhys() {
+ return new LE_PHYs( getRxPhysImpl() );
+ }
+ private native byte getRxPhysImpl();
+
+ @Override
public final HCIStatusCode disconnect() {
if( isConnected.get() ) {
return HCIStatusCode.get( disconnectImpl() ); // event callbacks will be generated by implementation
@@ -415,7 +450,7 @@ public class DBTDevice extends DBTObject implements BTDevice
@Override
public final boolean isValid() { return super.isValid() /* && isValidImpl() */; }
- // public native boolean isValidImpl();
+ // private native boolean isValidImpl();
@Override
public List<BTGattService> getServices() {
diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx
index 6a8303bd..a7ee582e 100644
--- a/java/jni/direct_bt/DBTAdapter.cxx
+++ b/java/jni/direct_bt/DBTAdapter.cxx
@@ -765,6 +765,17 @@ jboolean Java_jau_direct_1bt_DBTAdapter_isValidImpl(JNIEnv *env, jobject obj)
return JNI_FALSE;
}
+jlong Java_jau_direct_1bt_DBTAdapter_getLEFeaturesImpl(JNIEnv *env, jobject obj)
+{
+ try {
+ BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj);
+ return (jlong) number( adapter->getLEFeatures() );
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return JNI_FALSE;
+}
+
jbyte Java_jau_direct_1bt_DBTAdapter_startDiscoveryImpl(JNIEnv *env, jobject obj, jboolean keepAlive, jboolean le_scan_active,
jshort le_scan_interval, jshort le_scan_window,
jbyte filter_policy)
@@ -913,6 +924,23 @@ jbyte Java_jau_direct_1bt_DBTAdapter_resetImpl(JNIEnv *env, jobject obj) {
return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE);
}
+jbyte Java_jau_direct_1bt_DBTAdapter_setDefaultLE_1PHYImpl(JNIEnv *env, jobject obj,
+ jboolean tryTx, jboolean tryRx,
+ jbyte jTx, jbyte jRx) {
+ try {
+ BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj);
+ jau::JavaGlobalObj::check(adapter->getJavaObject(), E_FILE_LINE);
+
+ const LE_PHYs Tx = static_cast<LE_PHYs>(jTx);
+ const LE_PHYs Rx = static_cast<LE_PHYs>(jRx);
+
+ return number ( adapter->setDefaultLE_PHY(tryTx, tryRx, Tx, Rx) );
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE);
+}
+
jstring Java_jau_direct_1bt_DBTAdapter_getNameImpl(JNIEnv *env, jobject obj) {
try {
BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj);
diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx
index 13ef92c1..d37f76df 100644
--- a/java/jni/direct_bt/DBTDevice.cxx
+++ b/java/jni/direct_bt/DBTDevice.cxx
@@ -324,6 +324,90 @@ jbyte Java_jau_direct_1bt_DBTDevice_getRoleImpl(JNIEnv *env, jobject obj)
return (jbyte) number( BTRole::None );
}
+jbyte Java_jau_direct_1bt_DBTDevice_getConnectedLE_1PHYImpl(JNIEnv *env, jobject obj,
+ jbyteArray jresTx, jbyteArray jresRx) {
+ try {
+ BTDevice *device = getJavaUplinkObject<BTDevice>(env, obj);
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+
+ if( nullptr == jresTx ) {
+ throw IllegalArgumentException("resTx byte array null", E_FILE_LINE);
+ }
+ if( nullptr == jresRx ) {
+ throw IllegalArgumentException("resRx byte array null", E_FILE_LINE);
+ }
+
+ const size_t resTx_size = env->GetArrayLength(jresTx);
+ if( 1 > resTx_size ) {
+ throw IllegalArgumentException("resTx byte array "+std::to_string(resTx_size)+" < 1", E_FILE_LINE);
+ }
+ const size_t resRx_size = env->GetArrayLength(jresRx);
+ if( 1 > resRx_size ) {
+ throw IllegalArgumentException("resRx byte array "+std::to_string(resRx_size)+" < 1", E_FILE_LINE);
+ }
+
+ JNICriticalArray<uint8_t, jbyteArray> criticalArrayTx(env); // RAII - release
+ uint8_t * resTx_ptr = criticalArrayTx.get(jresTx, criticalArrayTx.Mode::UPDATE_AND_RELEASE);
+ if( NULL == resTx_ptr ) {
+ throw InternalError("GetPrimitiveArrayCritical(resTx byte array) is null", E_FILE_LINE);
+ }
+ JNICriticalArray<uint8_t, jbyteArray> criticalArrayRx(env); // RAII - release
+ uint8_t * resRx_ptr = criticalArrayRx.get(jresRx, criticalArrayTx.Mode::UPDATE_AND_RELEASE);
+ if( NULL == resRx_ptr ) {
+ throw InternalError("GetPrimitiveArrayCritical(resRx byte array) is null", E_FILE_LINE);
+ }
+
+ LE_PHYs& resTx = *reinterpret_cast<LE_PHYs *>(resTx_ptr);
+ LE_PHYs& resRx = *reinterpret_cast<LE_PHYs *>(resRx_ptr);
+
+ return number( device->getConnectedLE_PHY(resTx, resRx) );
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE);
+}
+
+jbyte Java_jau_direct_1bt_DBTDevice_setConnectedLE_1PHYImpl(JNIEnv *env, jobject obj,
+ jboolean tryTx, jboolean tryRx,
+ jbyte jTx, jbyte jRx) {
+ try {
+ BTDevice *device = getJavaUplinkObject<BTDevice>(env, obj);
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+
+ const LE_PHYs Tx = static_cast<LE_PHYs>(jTx);
+ const LE_PHYs Rx = static_cast<LE_PHYs>(jRx);
+
+ return number ( device->setConnectedLE_PHY(tryTx, tryRx, Tx, Rx) );
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE);
+}
+
+jbyte Java_jau_direct_1bt_DBTDevice_getTxPhysImpl(JNIEnv *env, jobject obj) {
+ try {
+ BTDevice *device = getJavaUplinkObject<BTDevice>(env, obj);
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+
+ return number( device->getTxPhys() );
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE);
+}
+
+jbyte Java_jau_direct_1bt_DBTDevice_getRxPhysImpl(JNIEnv *env, jobject obj) {
+ try {
+ BTDevice *device = getJavaUplinkObject<BTDevice>(env, obj);
+ JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE);
+
+ return number( device->getRxPhys() );
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE);
+}
+
jbyte Java_jau_direct_1bt_DBTDevice_disconnectImpl(JNIEnv *env, jobject obj)
{
try {
diff --git a/java/org/direct_bt/BTAdapter.java b/java/org/direct_bt/BTAdapter.java
index da6d4c14..201837e5 100644
--- a/java/org/direct_bt/BTAdapter.java
+++ b/java/org/direct_bt/BTAdapter.java
@@ -423,6 +423,15 @@ public interface BTAdapter extends BTObject
boolean isValid();
/**
+ * Return {@link LE_Features} for this controller.
+ * <pre>
+ * BT Core Spec v5.2: Vol 6, Part B, 4.6 (LE LL) Feature Support
+ * </pre>
+ * @since 2.4.0
+ */
+ LE_Features getLEFeatures();
+
+ /**
* Returns the power state the adapter.
* <p>
* Consider using {@link #isPowered()}
@@ -521,6 +530,24 @@ public interface BTAdapter extends BTObject
*/
HCIStatusCode reset();
+ /**
+ * Sets default preference of LE_PHYs.
+ *
+ * BT Core Spec v5.2: Vol 4, Part E, 7.8.49 LE Set PHY command
+ *
+ * @param tryTx if true, host has preference for given Tx LE_PHYs
+ * @param tryRx if true, host has preference for given Rx LE_PHYs
+ * @param Tx transmitter LE_PHYs of preference if tryTx is true, otherwise ignored
+ * @param Rx receiver LE_PHYs of preference if tryRx is true, otherwise ignored
+ * @return
+ * @see BTDevice#getTxPhys()
+ * @see BTDevice#getRxPhys()
+ * @see BTDevice#getConnectedLE_PHY(LE_PHYs[], LE_PHYs[])
+ * @see BTDevice#setConnectedLE_PHY(boolean, boolean, LE_PHYs, LE_PHYs)
+ * @since 2.4.0
+ */
+ HCIStatusCode setDefaultLE_PHY(final boolean tryTx, final boolean tryRx, final LE_PHYs Tx, final LE_PHYs Rx);
+
/** Returns the discoverable state the adapter.
* @return The discoverable state of the adapter.
*/
diff --git a/java/org/direct_bt/BTDevice.java b/java/org/direct_bt/BTDevice.java
index caca57c0..cbe5b2d9 100644
--- a/java/org/direct_bt/BTDevice.java
+++ b/java/org/direct_bt/BTDevice.java
@@ -660,6 +660,68 @@ public interface BTDevice extends BTObject
*/
short getConnectionHandle();
+ /**
+ * Request and return LE_PHYs bit for the given connection.
+ * <pre>
+ * BT Core Spec v5.2: Vol 4, Part E, 7.8.47 LE Read PHY command
+ * </pre>
+ * @param resRx array for one resulting receiver LE_PHYs bit
+ * @param resTx array for one resulting transmitter LE_PHYs bit
+ * @return HCIStatusCode
+ * @see #getTxPhys()
+ * @see #getRxPhys()
+ * @see #getConnectedLE_PHY(LE_PHYs[], LE_PHYs[])
+ * @see #setConnectedLE_PHY(boolean, boolean, LE_PHYs, LE_PHYs)
+ * @see BTAdapter#setDefaultLE_PHY(boolean, boolean, LE_PHYs, LE_PHYs)
+ * @since 2.4.0
+ */
+ HCIStatusCode getConnectedLE_PHY(LE_PHYs[/*1*/] resRx, LE_PHYs[/*1*/] resTx);
+
+ /**
+ * Return the Tx LE_PHYs as notified via LE_PHY_UPDATE_COMPLETE
+ * or retrieved via {@link #getConnectedLE_PHY(LE_PHYs[], LE_PHYs[])}.
+ * @see #getTxPhys()
+ * @see #getRxPhys()
+ * @see #getConnectedLE_PHY(LE_PHYs[], LE_PHYs[])
+ * @see #setConnectedLE_PHY(boolean, boolean, LE_PHYs, LE_PHYs)
+ * @see BTAdapter#setDefaultLE_PHY(boolean, boolean, LE_PHYs, LE_PHYs)
+ * @since 2.4.0
+ */
+ LE_PHYs getTxPhys();
+
+ /**
+ * Return the Rx LE_PHYs as notified via LE_PHY_UPDATE_COMPLETE
+ * or retrieved via {@link #getConnectedLE_PHY(LE_PHYs[], LE_PHYs[])}.
+ * @see #getTxPhys()
+ * @see #getRxPhys()
+ * @see #getConnectedLE_PHY(LE_PHYs[], LE_PHYs[])
+ * @see #setConnectedLE_PHY(boolean, boolean, LE_PHYs, LE_PHYs)
+ * @see BTAdapter#setDefaultLE_PHY(boolean, boolean, LE_PHYs, LE_PHYs)
+ * @since 2.4.0
+ */
+ LE_PHYs getRxPhys();
+
+
+ /**
+ * Sets preference of used LE_PHYs for the given connection.
+ *
+ * BT Core Spec v5.2: Vol 4, Part E, 7.8.49 LE Set PHY command
+ *
+ * @param tryTx if true, host has preference for given Tx LE_PHYs
+ * @param tryRx if true, host has preference for given Rx LE_PHYs
+ * @param Tx transmitter LE_PHYs of preference if tryTx is true, otherwise ignored
+ * @param Rx receiver LE_PHYs of preference if tryRx is true, otherwise ignored
+ * @return
+ * @see #getTxPhys()
+ * @see #getRxPhys()
+ * @see #getConnectedLE_PHY(LE_PHYs[], LE_PHYs[])
+ * @see #setConnectedLE_PHY(boolean, boolean, LE_PHYs, LE_PHYs)
+ * @see BTAdapter#setDefaultLE_PHY(boolean, boolean, LE_PHYs, LE_PHYs)
+ * @since 2.4.0
+ */
+ HCIStatusCode setConnectedLE_PHY(final boolean tryTx, final boolean tryRx,
+ final LE_PHYs Tx, final LE_PHYs Rx);
+
/** Returns the adapter on which this device was discovered or
* connected.
* @return The adapter.
diff --git a/java/org/direct_bt/LE_Features.java b/java/org/direct_bt/LE_Features.java
new file mode 100644
index 00000000..e5f893d4
--- /dev/null
+++ b/java/org/direct_bt/LE_Features.java
@@ -0,0 +1,119 @@
+/**
+ * Author: Sven Gothel <[email protected]>
+ * 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
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package org.direct_bt;
+
+/**
+ * LE Link Layer Feature Set (bitmask)
+ * <pre>
+ * BT Core Spec v5.2: Vol 6, Part B, 4.6 (LE LL) Feature Support
+ *
+ * BT Core Spec v5.2: Vol 4, Part E, 7.8.3 LE Read Local Supported Features command
+ *
+ * BT Core Spec v5.2: Vol 4, Part E, 7.8.21 LE Read Remote Features command
+ * BT Core Spec v5.2: Vol 4, Part E, 7.7.65.4 LE Read Remote Features Complete event
+ *
+ * BT Core Spec v5.2: Vol 6, Part B, 7.8.115 LE Set Host Feature Command
+ * </pre>
+ *
+ * @since 2.4.0
+ */
+public class LE_Features {
+
+ /**
+ * Each enum represents a 'LE Link Layer Feature' bit value.
+ *
+ * @since 2.4.0
+ */
+ public enum Feature {
+ LE_Encryption(0),
+ Conn_Param_Req_Proc(1),
+ Ext_Rej_Ind(2),
+ SlaveInit_Feat_Exchg(3),
+ LE_Ping(4),
+ LE_Data_Pkt_Len_Ext(5),
+ LL_Privacy(6),
+ Ext_Scan_Filter_Pol(7),
+ LE_2M_PHY(8),
+ Stable_Mod_Idx_Tx(9),
+ Stable_Mod_Idx_Rx(10),
+ LE_Coded_PHY(11),
+ LE_Ext_Adv(12),
+ LE_Per_Adv(13),
+ Chan_Sel_Algo_2(14),
+ LE_Pwr_Cls_1(15),
+ Min_Num_Used_Chan_Proc(16),
+ Conn_CTE_Req(17),
+ Conn_CTE_Res(18),
+ ConnLess_CTE_Tx(19),
+ ConnLess_CTE_Rx(20),
+ AoD(21),
+ AoA(22),
+ Rx_Const_Tone_Ext(23),
+ Per_Adv_Sync_Tx_Sender(24),
+ Per_Adv_Sync_Tx_Rec(25),
+ Zzz_Clk_Acc_Upd(26),
+ Rem_Pub_Key_Val(27),
+ Conn_Iso_Stream_Master(28),
+ Conn_Iso_Stream_Slave(29),
+ Iso_Brdcst(30),
+ Sync_Rx(31),
+ Iso_Chan(32),
+ LE_Pwr_Ctrl_Req(33),
+ LE_Pwr_Chg_Ind(34),
+ LE_Path_Loss_Mon(35);
+
+ Feature(final int v) {
+ value = 1L << v;
+ }
+ public final long value;
+ }
+
+ public long mask;
+
+
+ public LE_Features(final long v) {
+ mask = v;
+ }
+
+ public boolean isSet(final Feature bit) { return 0 != ( mask & bit.value ); }
+ public void set(final Feature bit) { mask = mask | bit.value; }
+
+ @Override
+ public String toString() {
+ int count = 0;
+ final StringBuilder out = new StringBuilder();
+ for (final Feature f : Feature.values()) {
+ if( isSet(f) ) {
+ if( 0 < count ) { out.append(", "); }
+ out.append(f.name()); count++;
+ }
+ }
+ if( 1 < count ) {
+ out.insert(0, "[");
+ out.append("]");
+ }
+ return out.toString();
+ }
+}
diff --git a/java/org/direct_bt/LE_PHYs.java b/java/org/direct_bt/LE_PHYs.java
new file mode 100644
index 00000000..618a10d9
--- /dev/null
+++ b/java/org/direct_bt/LE_PHYs.java
@@ -0,0 +1,85 @@
+/**
+ * Author: Sven Gothel <[email protected]>
+ * 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
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package org.direct_bt;
+
+/**
+ * LE Transport PHY bit values (bitmask)
+ * <pre>
+ * BT Core Spec v5.2: Vol 4, Part E, 7.8.47 LE Read PHY command (we transfer the sequential value to this bitmask for unification)
+ * BT Core Spec v5.2: Vol 4, Part E, 7.8.48 LE Set Default PHY command
+ * </pre>
+ *
+ * @since 2.4.0
+ */
+public class LE_PHYs {
+
+ /**
+ * Each enum represents a 'LE Transport PHY' bit value.
+ *
+ * @since 2.4.0
+ */
+ public enum PHY {
+ LE_1M(0),
+ LE_2M(1),
+ LE_CODED(2);
+
+ PHY(final int v) {
+ value = (byte)( 1 << v );
+ }
+ public final byte value;
+ }
+
+ public byte mask;
+
+ public LE_PHYs() {
+ mask = 0;
+ }
+ public LE_PHYs(final byte v) {
+ mask = v;
+ }
+ public LE_PHYs(final PHY v) {
+ mask = v.value;
+ }
+
+ public boolean isSet(final PHY bit) { return 0 != ( mask & bit.value ); }
+ public void set(final PHY bit) { mask = (byte) ( mask | bit.value ); }
+
+ @Override
+ public String toString() {
+ int count = 0;
+ final StringBuilder out = new StringBuilder();
+ for (final PHY f : PHY.values()) {
+ if( isSet(f) ) {
+ if( 0 < count ) { out.append(", "); }
+ out.append(f.name()); count++;
+ }
+ }
+ if( 1 < count ) {
+ out.insert(0, "[");
+ out.append("]");
+ }
+ return out.toString();
+ }
+}