From 8b475db0e662e00a1577b7a6090c3a99857560c8 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 24 Sep 2021 13:30:43 +0200 Subject: 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 --- java/jau/direct_bt/DBTAdapter.java | 21 ++++++- java/jau/direct_bt/DBTDevice.java | 37 ++++++++++- java/jni/direct_bt/DBTAdapter.cxx | 28 +++++++++ java/jni/direct_bt/DBTDevice.cxx | 84 +++++++++++++++++++++++++ java/org/direct_bt/BTAdapter.java | 27 ++++++++ java/org/direct_bt/BTDevice.java | 62 +++++++++++++++++++ java/org/direct_bt/LE_Features.java | 119 ++++++++++++++++++++++++++++++++++++ java/org/direct_bt/LE_PHYs.java | 85 ++++++++++++++++++++++++++ 8 files changed, 459 insertions(+), 4 deletions(-) create mode 100644 java/org/direct_bt/LE_Features.java create mode 100644 java/org/direct_bt/LE_PHYs.java (limited to 'java') 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; @@ -298,6 +300,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); @@ -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; @@ -223,6 +224,40 @@ public class DBTDevice extends DBTObject implements BTDevice @Override 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() ) { @@ -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 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(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(env, obj); + jau::JavaGlobalObj::check(adapter->getJavaObject(), E_FILE_LINE); + + const LE_PHYs Tx = static_cast(jTx); + const LE_PHYs Rx = static_cast(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(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(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 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 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(resTx_ptr); + LE_PHYs& resRx = *reinterpret_cast(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(env, obj); + JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE); + + const LE_PHYs Tx = static_cast(jTx); + const LE_PHYs Rx = static_cast(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(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(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 @@ -422,6 +422,15 @@ public interface BTAdapter extends BTObject */ boolean isValid(); + /** + * Return {@link LE_Features} for this controller. + *
+     * BT Core Spec v5.2: Vol 6, Part B, 4.6 (LE LL) Feature Support
+     * 
+ * @since 2.4.0 + */ + LE_Features getLEFeatures(); + /** * Returns the power state the adapter. *

@@ -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. + *

+     * BT Core Spec v5.2: Vol 4, Part E, 7.8.47 LE Read PHY command
+     * 
+ * @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 + * 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) + *
+ * 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
+ * 
+ * + * @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 + * 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) + *
+ * 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
+ * 
+ * + * @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(); + } +} -- cgit v1.2.3