Skip to content

Commit

Permalink
Changed PhyPair, RxBlePhy and RxBlePhyOption to interfaces. Removed R…
Browse files Browse the repository at this point in the history
…xBlePhy.UNKNOWN. Closed to modification, opened to extension.
  • Loading branch information
dariuszseweryn committed Jan 4, 2024
1 parent e302fda commit bd822a8
Show file tree
Hide file tree
Showing 14 changed files with 415 additions and 191 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import androidx.annotation.NonNull;

import android.bluetooth.BluetoothGattService;
import android.util.Log;

import androidx.annotation.NonNull;

import com.polidea.rxandroidble2.ConnectionParameters;
import com.polidea.rxandroidble2.NotificationSetupMode;
import com.polidea.rxandroidble2.PhyPair;
Expand All @@ -20,22 +20,23 @@
import com.polidea.rxandroidble2.exceptions.BleGattCharacteristicException;
import com.polidea.rxandroidble2.exceptions.BleGattDescriptorException;
import com.polidea.rxandroidble2.exceptions.BleGattOperationType;
import com.polidea.rxandroidble2.internal.PhyPairImpl;
import com.polidea.rxandroidble2.internal.Priority;
import com.polidea.rxandroidble2.internal.connection.ImmediateSerializedBatchAckStrategy;
import com.polidea.rxandroidble2.internal.util.ObservableUtil;
import com.polidea.rxandroidble2.mockrxandroidble.callbacks.results.RxBleGattReadResultMock;
import com.polidea.rxandroidble2.mockrxandroidble.callbacks.results.RxBleGattWriteResultMock;
import com.polidea.rxandroidble2.mockrxandroidble.callbacks.RxBleCharacteristicReadCallback;
import com.polidea.rxandroidble2.mockrxandroidble.callbacks.RxBleCharacteristicWriteCallback;
import com.polidea.rxandroidble2.mockrxandroidble.callbacks.RxBleDescriptorReadCallback;
import com.polidea.rxandroidble2.mockrxandroidble.callbacks.RxBleDescriptorWriteCallback;
import com.polidea.rxandroidble2.mockrxandroidble.callbacks.results.RxBleGattReadResultMock;
import com.polidea.rxandroidble2.mockrxandroidble.callbacks.results.RxBleGattWriteResultMock;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -78,7 +79,7 @@ public class RxBleConnectionMock implements RxBleConnection {
private RxBleDeviceServices rxBleDeviceServices;
private int rssi;
private int currentMtu = 23;
private PhyPair phy = new PhyPair(RxBlePhy.PHY_1M, RxBlePhy.PHY_1M);
private PhyPair phy = new PhyPairImpl(RxBlePhy.PHY_1M, RxBlePhy.PHY_1M);
private Map<UUID, Observable<byte[]>> characteristicNotificationSources;
private Map<UUID, RxBleCharacteristicReadCallback> characteristicReadCallbacks;
private Map<UUID, RxBleCharacteristicWriteCallback> characteristicWriteCallbacks;
Expand Down Expand Up @@ -135,30 +136,13 @@ public Single<PhyPair> readPhy() {
}

@Override
public Single<PhyPair> setPreferredPhy(EnumSet<RxBlePhy> txPhy, EnumSet<RxBlePhy> rxPhy, RxBlePhyOption phyOptions) {
public Single<PhyPair> setPreferredPhy(Set<RxBlePhy> txPhy, Set<RxBlePhy> rxPhy, RxBlePhyOption phyOptions) {
return Single.fromCallable(() -> {
final Iterator<RxBlePhy> txPhyIterator = txPhy.iterator();
final Iterator<RxBlePhy> rxPhyIterator = rxPhy.iterator();
int tx = RxBlePhy.PHY_1M.getValue();
int rx = RxBlePhy.PHY_1M.getValue();

while (txPhyIterator.hasNext()) {
final int value = txPhyIterator.next().getValue();
if (value != RxBlePhy.PHY_UNKNOWN.getValue()) {
tx = value;
break;
}
}

while (rxPhyIterator.hasNext()) {
final int value = rxPhyIterator.next().getValue();
if (value != RxBlePhy.PHY_UNKNOWN.getValue()) {
rx = value;
break;
}
}

phy = new PhyPair(RxBlePhy.fromInt(tx), RxBlePhy.fromInt(rx));
phy = new PhyPairImpl(
txPhyIterator.hasNext() ? txPhyIterator.next() : RxBlePhy.PHY_1M,
rxPhyIterator.hasNext() ? rxPhyIterator.next() : RxBlePhy.PHY_1M);
return phy;
});
}
Expand Down
56 changes: 13 additions & 43 deletions rxandroidble/src/main/java/com/polidea/rxandroidble2/PhyPair.java
Original file line number Diff line number Diff line change
@@ -1,53 +1,23 @@
package com.polidea.rxandroidble2;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class PhyPair {
public final RxBlePhy txPhy;
public final RxBlePhy rxPhy;
import java.util.Set;

public PhyPair(@NonNull final RxBlePhy txPhy, @NonNull final RxBlePhy rxPhy) {
this.txPhy = txPhy;
this.rxPhy = rxPhy;
}
/**
* The interface used for results of {@link RxBleConnection#readPhy()} and {@link RxBleConnection#setPreferredPhy(Set, Set, RxBlePhyOption)}
*/
public interface PhyPair {

@NonNull
public static PhyPair fromGattCallback(int txPhy, int rxPhy, int status) {
RxBlePhy tx = RxBlePhy.PHY_UNKNOWN;
RxBlePhy rx = RxBlePhy.PHY_UNKNOWN;

// GATT callbacks do not use the same LE Coded value as it does for the setPreferredPhy function. GATT
// callbacks use the unmasked value (BluetoothDevice.PHY_LE_CODED) and setPreferredPhy uses the mask value
// (BluetoothDevice.PHY_LE_CODED_MASK). Explicitly check for BluetoothDevice.PHY_LE_CODED here and manually
// set it to RxBlePhy.PHY_CODED since it too uses the masked version. This will abstract that confusion
// away from the user and make it unified.
if (status == BluetoothGatt.GATT_SUCCESS) {
tx = txPhy == BluetoothDevice.PHY_LE_CODED ? RxBlePhy.PHY_CODED : RxBlePhy.fromInt(txPhy);
rx = rxPhy == BluetoothDevice.PHY_LE_CODED ? RxBlePhy.PHY_CODED : RxBlePhy.fromInt(rxPhy);
}

return new PhyPair(tx, rx);
}

@Override
public int hashCode() {
return txPhy.hashCode() ^ rxPhy.hashCode();
}

@Override
public boolean equals(@Nullable Object obj) {
if (obj == this) {
return true;
}

if (obj == null || getClass() != obj.getClass()) {
return false;
}

return txPhy.equals(rxPhy);
}
RxBlePhy getTxPhy();

@NonNull
RxBlePhy getRxPhy();

int hashCode();

boolean equals(@Nullable Object obj);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.EnumSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -595,17 +595,18 @@ Completable requestConnectionPriority(
/**
* Performs set preferred PHY request.
*
* @param txPhy Sets the preferred transmitter (Tx) PHY.
* @param rxPhy Sets the preferred receiver (Rx) PHY.
* @param phyOptions Sets the preferred coding to use when transmitting on the LE Coded PHY.
* @param txPhy Sets the preferred transmitter (Tx) PHY. Use static values from RxBlePhy.
* @param rxPhy Sets the preferred receiver (Rx) PHY. Use static values from RxBlePhy.
* @param phyOptions Sets the preferred coding to use when transmitting on the LE Coded PHY. Use one of static values from
* RxBlePhyOption.
* @return Observable emitting negotiated PHY values pair.
* @throws BleGattException in case of GATT operation error with {@link BleGattOperationType#PHY_UPDATE} type.
* @implNote RxBlePhy.PHY_UNKNOWN is used for the onPhyRead and onPhyUpdate callbacks in cases where the GATT operation
* was not successful. Using RxBlePhy.PHY_UNKNOWN as the sole value in either of the txPhy or rxPhy parameters
* will result in the default value being used (RxBlePhy.PHY_1M).
* @implNote In case the library is outdated and does not implement expected pre-defined static objects to use, one can implement their
* own objects and pass as parameters which should unblock the use-case. In this case please consider making a PR to the
* library.
*/
@RequiresApi(26 /* Build.VERSION_CODES.O */)
Single<PhyPair> setPreferredPhy(EnumSet<RxBlePhy> txPhy, EnumSet<RxBlePhy> rxPhy, RxBlePhyOption phyOptions);
Single<PhyPair> setPreferredPhy(Set<RxBlePhy> txPhy, Set<RxBlePhy> rxPhy, RxBlePhyOption phyOptions);

/**
* <b>This method requires deep knowledge of RxAndroidBLE internals. Use it only as a last resort if you know
Expand Down
84 changes: 16 additions & 68 deletions rxandroidble/src/main/java/com/polidea/rxandroidble2/RxBlePhy.java
Original file line number Diff line number Diff line change
@@ -1,92 +1,40 @@
package com.polidea.rxandroidble2;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.bluetooth.BluetoothDevice;

import com.polidea.rxandroidble2.internal.RxBleLog;
import com.polidea.rxandroidble2.internal.RxBlePhyImpl;

import java.util.EnumSet;
import java.util.Iterator;
import java.util.Set;

public enum RxBlePhy {
/**
* Unknown Bluetooth PHY. Used if the PHY couldn't be determined.
*
* @implNote If this value is used when calling the setPreferredPhy then it will default to PHY_1M
*/
PHY_UNKNOWN(0),
/**
* The interface used in {@link Set} for requesting PHY when calling {@link RxBleConnection#setPreferredPhy(Set, Set, RxBlePhyOption)} and
* inside {@link PhyPair} as results of {@link RxBleConnection#readPhy()} and
* {@link RxBleConnection#setPreferredPhy(Set, Set, RxBlePhyOption)}
*/
public interface RxBlePhy {

/**
* Bluetooth LE 1M PHY.
*/
PHY_1M(1),
RxBlePhy PHY_1M = RxBlePhyImpl.PHY_1M;

/**
* Bluetooth LE 2M PHY.
*/
PHY_2M(1 << 1),
RxBlePhy PHY_2M = RxBlePhyImpl.PHY_2M;

/**
* Bluetooth LE Coded PHY.
*/
PHY_CODED(1 << 2);

private final int value;

RxBlePhy(final int value) {
this.value = value;
}

public int getValue() {
return value;
}
RxBlePhy PHY_CODED = RxBlePhyImpl.PHY_CODED;

/**
* Function used to get the PHY enum value from an integer.
*
* @param value The integer value to try to get he PHY enum value for.
*
* @return The PHY enum value if a valid one was found; otherwise, RxBlePhy.PHY_UNKNOWN is returned.
* Corresponds to e.g. {@link BluetoothDevice#PHY_LE_CODED_MASK}
*/
@NonNull
public static RxBlePhy fromInt(final int value) {
for (final RxBlePhy entry : RxBlePhy.values()) {
if (entry.getValue() == value) {
return entry;
}
}
RxBleLog.w("%d is not a valid PHY value.", value);
return RxBlePhy.PHY_UNKNOWN;
}
int getMask();

/**
* Function used to convert the specified enum set to the equivalent values mask.
*
* @param set The enum set to compute the values mask for.
*
* @return If the set is NULL, empty, or only contains the unknown value (RxBlePhy.PHY_UNKNOWN), then the default
* value mask, RxBlePhy.PHY_1M, is returned. Otherwise, the resulting values mask is returned.
* Corresponds to e.g. {@link BluetoothDevice#PHY_LE_CODED}
*/
public static int enumSetToValuesMask(@Nullable final EnumSet<RxBlePhy> set) {
if (set == null || set.size() == 0) {
return RxBlePhy.PHY_1M.getValue();
}

final Iterator<RxBlePhy> iterator = set.iterator();

if (set.size() == 1) {
final int requestedValue = iterator.next().getValue();
final boolean isUnknown = requestedValue == RxBlePhy.PHY_UNKNOWN.getValue();
return isUnknown ? RxBlePhy.PHY_1M.getValue() : requestedValue;
}

int result = 0;

while (iterator.hasNext()) {
final int requestedValue = iterator.next().getValue();
result |= requestedValue;
}

return result;
}
int getValue();
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
package com.polidea.rxandroidble2;

import com.polidea.rxandroidble2.internal.RxBlePhyOptionImpl;

/**
* Coding to be used when transmitting on the LE Coded PHY.
*/
public enum RxBlePhyOption {
public interface RxBlePhyOption {
/**
* No preferred coding.
*/
PHY_OPTION_NO_PREFERRED(0),
RxBlePhyOption PHY_OPTION_NO_PREFERRED = RxBlePhyOptionImpl.PHY_OPTION_NO_PREFERRED;

/**
* Prefer the S=2 coding.
*/
PHY_OPTION_S2(1),
RxBlePhyOption PHY_OPTION_S2 = RxBlePhyOptionImpl.PHY_OPTION_S2;

/**
* Prefer the S=8 coding.
*/
PHY_OPTION_S8(2);

private final int value;

RxBlePhyOption(final int value) {
this.value = value;
}
RxBlePhyOption PHY_OPTION_S8 = RxBlePhyOptionImpl.PHY_OPTION_S8;

public int getValue() {
return value;
}
/**
*
* @return integer value representing PHY option, e.g. {@link android.bluetooth.BluetoothDevice#PHY_OPTION_S2}
*/
int getValue();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.polidea.rxandroidble2.internal;


import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.polidea.rxandroidble2.PhyPair;
import com.polidea.rxandroidble2.RxBlePhy;

import java.util.Objects;

public class PhyPairImpl implements PhyPair {
public final RxBlePhy txPhy;
public final RxBlePhy rxPhy;

public PhyPairImpl(@NonNull final RxBlePhy txPhy, @NonNull final RxBlePhy rxPhy) {
this.txPhy = txPhy;
this.rxPhy = rxPhy;
}

@NonNull
@Override
public RxBlePhy getTxPhy() {
return txPhy;
}

@NonNull
@Override
public RxBlePhy getRxPhy() {
return rxPhy;
}

@Override
public int hashCode() {
return Objects.hash(rxPhy, txPhy);
}

@Override
public boolean equals(@Nullable Object obj) {
if (obj == this) return true;
if (!(obj instanceof PhyPair)) return false;
PhyPair phyPair = (PhyPair) obj;
return txPhy.equals(phyPair.getTxPhy()) && rxPhy.equals(phyPair.getRxPhy());
}
}
Loading

0 comments on commit bd822a8

Please sign in to comment.