mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Pebble: Make connection to new Pebble 2 Duo work in recovery mode
This is just a first hack, it is unclear how to deal with MTU etc yet. I was able to pair and connect after some tries, which is better than nothing
This commit is contained in:
+1
-1
@@ -188,7 +188,7 @@ class PebbleIoThread extends GBDeviceIoThread {
|
||||
deviceAddress = gbDevice.getVolatileAddress();
|
||||
}
|
||||
BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(deviceAddress);
|
||||
if (btDevice.getType() == BluetoothDevice.DEVICE_TYPE_LE) {
|
||||
if (btDevice.getType() == BluetoothDevice.DEVICE_TYPE_LE || btDevice.getType() == BluetoothDevice.DEVICE_TYPE_DUAL) {
|
||||
LOG.info("This is a Pebble 2 or Pebble-LE/Pebble Time LE, will use BLE");
|
||||
mInStream = new PipedInputStream();
|
||||
mOutStream = new PipedOutputStream();
|
||||
|
||||
+25
-20
@@ -16,6 +16,9 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.ble;
|
||||
|
||||
import static android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT16;
|
||||
import static android.bluetooth.BluetoothGattCharacteristic.PROPERTY_WRITE;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
@@ -36,9 +39,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WriteAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.BondingUtil;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
import static android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT16;
|
||||
import static android.bluetooth.BluetoothGattCharacteristic.PROPERTY_WRITE;
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
class PebbleGATTClient extends BluetoothGattCallback {
|
||||
|
||||
@@ -61,7 +61,7 @@ class PebbleGATTClient extends BluetoothGattCallback {
|
||||
private final Context mContext;
|
||||
private final PebbleLESupport mPebbleLESupport;
|
||||
|
||||
private boolean oldPebble = false;
|
||||
private boolean hasConnectivityCharacteristics = false;
|
||||
private final boolean doPairing = true;
|
||||
private final boolean removeBond = false;
|
||||
private BluetoothGatt mBluetoothGatt;
|
||||
@@ -82,12 +82,12 @@ class PebbleGATTClient extends BluetoothGattCallback {
|
||||
|
||||
if (characteristic.getUuid().equals(MTU_CHARACTERISTIC)) {
|
||||
int newMTU = characteristic.getIntValue(FORMAT_UINT16, 0);
|
||||
LOG.info("Pebble requested MTU: " + newMTU);
|
||||
LOG.info("Pebble requested MTU: {}", newMTU);
|
||||
mPebbleLESupport.setMTU(newMTU);
|
||||
} else if (characteristic.getUuid().equals(PPOGATT_CHARACTERISTIC_READ)) {
|
||||
mPebbleLESupport.handlePPoGATTPacket(characteristic.getValue().clone());
|
||||
} else {
|
||||
LOG.info("onCharacteristicChanged() " + characteristic.getUuid().toString() + " " + GB.hexdump(characteristic.getValue(), 0, -1));
|
||||
LOG.info("onCharacteristicChanged() {} {}", characteristic.getUuid().toString(), GB.hexdump(characteristic.getValue(), 0, -1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,11 +97,11 @@ class PebbleGATTClient extends BluetoothGattCallback {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.info("onCharacteristicRead() status = " + status);
|
||||
LOG.info("onCharacteristicRead() status = {}", status);
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
LOG.info("onCharacteristicRead() " + characteristic.getUuid().toString() + " " + GB.hexdump(characteristic.getValue(), 0, -1));
|
||||
LOG.info("onCharacteristicRead() {} {}", characteristic.getUuid().toString(), GB.hexdump(characteristic.getValue(), 0, -1));
|
||||
|
||||
if (oldPebble) {
|
||||
if (hasConnectivityCharacteristics) {
|
||||
subscribeToConnectivity(gatt);
|
||||
} else {
|
||||
subscribeToConnectionParams(gatt);
|
||||
@@ -141,7 +141,7 @@ class PebbleGATTClient extends BluetoothGattCallback {
|
||||
} else if (characteristic.getUuid().equals(PAIRING_TRIGGER_CHARACTERISTIC) || characteristic.getUuid().equals(CONNECTIVITY_CHARACTERISTIC)) {
|
||||
//mBtDevice.createBond(); // did not work when last tried
|
||||
|
||||
if (oldPebble) {
|
||||
if (hasConnectivityCharacteristics) {
|
||||
subscribeToConnectivity(gatt);
|
||||
} else {
|
||||
subscribeToConnectionParams(gatt);
|
||||
@@ -182,13 +182,13 @@ class PebbleGATTClient extends BluetoothGattCallback {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.info("onServicesDiscovered() status = " + status);
|
||||
LOG.info("onServicesDiscovered() status = {}", status);
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
BluetoothGattCharacteristic connectionPararmharacteristic = gatt.getService(SERVICE_UUID).getCharacteristic(CONNECTION_PARAMETERS_CHARACTERISTIC);
|
||||
oldPebble = connectionPararmharacteristic == null;
|
||||
BluetoothGattCharacteristic connectionParamCharacteristic = gatt.getService(SERVICE_UUID).getCharacteristic(CONNECTION_PARAMETERS_CHARACTERISTIC);
|
||||
hasConnectivityCharacteristics = connectionParamCharacteristic == null;
|
||||
|
||||
if (oldPebble) {
|
||||
LOG.info("This seems to be an older le enabled pebble");
|
||||
if (hasConnectivityCharacteristics) {
|
||||
LOG.info("This seems to be an older le enabled Pebble (Pebble Time), or a 2025 Pebble");
|
||||
}
|
||||
|
||||
if (doPairing) {
|
||||
@@ -213,7 +213,7 @@ class PebbleGATTClient extends BluetoothGattCallback {
|
||||
gatt.readCharacteristic(characteristic);
|
||||
}
|
||||
} else {
|
||||
if (oldPebble) {
|
||||
if (hasConnectivityCharacteristics) {
|
||||
subscribeToConnectivity(gatt);
|
||||
} else {
|
||||
subscribeToConnectionParams(gatt);
|
||||
@@ -240,10 +240,15 @@ class PebbleGATTClient extends BluetoothGattCallback {
|
||||
}
|
||||
|
||||
private void subscribeToMTU(BluetoothGatt gatt) {
|
||||
LOG.info("subscribing to mtu characteristic");
|
||||
BluetoothGattDescriptor descriptor = gatt.getService(SERVICE_UUID).getCharacteristic(MTU_CHARACTERISTIC).getDescriptor(CHARACTERISTIC_CONFIGURATION_DESCRIPTOR);
|
||||
NotifyAction.writeDescriptor(gatt, descriptor, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
|
||||
gatt.setCharacteristicNotification(gatt.getService(SERVICE_UUID).getCharacteristic(MTU_CHARACTERISTIC), true);
|
||||
BluetoothGattCharacteristic characteristic = gatt.getService(SERVICE_UUID).getCharacteristic(MTU_CHARACTERISTIC);
|
||||
if (characteristic != null) {
|
||||
LOG.info("subscribing to mtu characteristic");
|
||||
BluetoothGattDescriptor descriptor = gatt.getService(SERVICE_UUID).getCharacteristic(MTU_CHARACTERISTIC).getDescriptor(CHARACTERISTIC_CONFIGURATION_DESCRIPTOR);
|
||||
NotifyAction.writeDescriptor(gatt, descriptor, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
|
||||
gatt.setCharacteristicNotification(gatt.getService(SERVICE_UUID).getCharacteristic(MTU_CHARACTERISTIC), true);
|
||||
} else {
|
||||
LOG.info("Could not find MTU Characteristic. This seems to be a 2025 Pebble");
|
||||
}
|
||||
}
|
||||
|
||||
private void subscribeToConnectionParams(BluetoothGatt gatt) {
|
||||
|
||||
+15
-15
@@ -38,22 +38,20 @@ public class PebbleLESupport {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PebbleLESupport.class);
|
||||
private static final AtomicLong THREAD_COUNTER = new AtomicLong(0L);
|
||||
|
||||
private final GBDevice mgbDevice;
|
||||
private final BluetoothDevice mBtDevice;
|
||||
private PipeReader mPipeReader;
|
||||
private PebbleGATTServer mPebbleGATTServer;
|
||||
private PebbleGATTClient mPebbleGATTClient;
|
||||
private PipedInputStream mPipedInputStream;
|
||||
private PipedOutputStream mPipedOutputStream;
|
||||
private final PipedInputStream mPipedInputStream;
|
||||
private final PipedOutputStream mPipedOutputStream;
|
||||
private int mMTU = 20;
|
||||
private int mMTULimit = Integer.MAX_VALUE;
|
||||
public boolean clientOnly = false; // currently experimental, and only possible for Pebble 2
|
||||
private int mMTULimit;
|
||||
public boolean clientOnly; // currently experimental, and only possible for Pebble 2
|
||||
private boolean mIsConnected = false;
|
||||
private HandlerThread mWriteHandlerThread;
|
||||
private Handler mWriteHandler;
|
||||
private final HandlerThread mWriteHandlerThread;
|
||||
private final Handler mWriteHandler;
|
||||
|
||||
public PebbleLESupport(Context context, GBDevice gbDevice, final BluetoothDevice btDevice, PipedInputStream pipedInputStream, PipedOutputStream pipedOutputStream) throws IOException {
|
||||
mgbDevice = gbDevice;
|
||||
mBtDevice = btDevice;
|
||||
mPipedInputStream = new PipedInputStream();
|
||||
mPipedOutputStream = new PipedOutputStream();
|
||||
@@ -69,14 +67,16 @@ public class PebbleLESupport {
|
||||
mWriteHandler = new Handler(mWriteHandlerThread.getLooper());
|
||||
mWriteHandler.post(() -> LOG.debug("started thread {}", Thread.currentThread().getName()));
|
||||
|
||||
mMTULimit = GBApplication.getDevicePrefs(mgbDevice).getInt("pebble_mtu_limit", 512);
|
||||
mMTULimit = GBApplication.getDevicePrefs(gbDevice).getInt("pebble_mtu_limit", 512);
|
||||
mMTULimit = Math.max(mMTULimit, 20);
|
||||
mMTULimit = Math.min(mMTULimit, 512);
|
||||
|
||||
clientOnly = GBApplication.getDevicePrefs(mgbDevice).getBoolean("pebble_gatt_clientonly", false);
|
||||
clientOnly = GBApplication.getDevicePrefs(gbDevice).getBoolean("pebble_gatt_clientonly", false);
|
||||
|
||||
if (!clientOnly) {
|
||||
mPebbleGATTServer = new PebbleGATTServer(this, context, mBtDevice);
|
||||
} else {
|
||||
LOG.info ("using client only mode");
|
||||
}
|
||||
if (clientOnly || mPebbleGATTServer.initialize()) {
|
||||
mPebbleGATTClient = new PebbleGATTClient(this, context, mBtDevice);
|
||||
@@ -94,9 +94,9 @@ public class PebbleLESupport {
|
||||
throw new IOException("connection failed");
|
||||
}
|
||||
|
||||
private void writeToPipedOutputStream(byte[] value, int offset, int count) {
|
||||
private void writeToPipedOutputStream(byte[] value, int count) {
|
||||
try {
|
||||
mPipedOutputStream.write(value, offset, count);
|
||||
mPipedOutputStream.write(value, 1, count);
|
||||
} catch (IOException e) {
|
||||
LOG.warn("error writing to output stream", e);
|
||||
}
|
||||
@@ -163,7 +163,7 @@ public class PebbleLESupport {
|
||||
int command = header & 7;
|
||||
int serial = header >> 3;
|
||||
if (command == 0x01) {
|
||||
LOG.info("got ACK for serial = " + serial);
|
||||
LOG.info("got ACK for serial = {}", serial);
|
||||
}
|
||||
if (command == 0x02) { // some request?
|
||||
LOG.info("got command 0x02");
|
||||
@@ -178,7 +178,7 @@ public class PebbleLESupport {
|
||||
|
||||
sendAckToPebble(serial);
|
||||
|
||||
writeToPipedOutputStream(value, 1, value.length - 1);
|
||||
writeToPipedOutputStream(value, value.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ public class PebbleLESupport {
|
||||
int srcPos = 0;
|
||||
int maxChunkSize = calcMaxWriteChunk(mMTU) - 1;
|
||||
while (payloadToSend > 0) {
|
||||
int chunkSize = (payloadToSend < maxChunkSize) ? payloadToSend : maxChunkSize;
|
||||
int chunkSize = Math.min(payloadToSend, maxChunkSize);
|
||||
byte[] outBuf = new byte[chunkSize + 1];
|
||||
outBuf[0] = (byte) ((mmSequence++ << 3) & 0xff);
|
||||
System.arraycopy(buf, srcPos, outBuf, 1, chunkSize);
|
||||
|
||||
Reference in New Issue
Block a user