1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-25 03:16:51 +01:00

Pebble2: WIP broken and disabled GATT client only support

This will eliminate the need for the Phone being a GATT Server and might lead
to better connection stability once it is ready.

NOTE: Enabling this in the code (change clientOnly=true in PebbleLESupport)
will only work for a few packets before in totally breaks, so only enable
if you want to fix it :P
This commit is contained in:
Andreas Shimokawa 2018-05-10 22:03:03 +02:00
parent bd012cab2a
commit f6131772d6
3 changed files with 105 additions and 47 deletions

View File

@ -47,7 +47,13 @@ class PebbleGATTClient extends BluetoothGattCallback {
private static final UUID CONNECTION_PARAMETERS_CHARACTERISTIC = UUID.fromString("00000005-328E-0FBB-C642-1AA6699BDADA");
private static final UUID CHARACTERISTIC_CONFIGURATION_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
private final BluetoothDevice mBtDevice;
//PPoGATT service (Pebble side)
private static final UUID PPOGATT_SERVICE_UUID = UUID.fromString("30000003-328E-0FBB-C642-1AA6699BDADA");
private static final UUID PPOGATT_CHARACTERISTIC_READ = UUID.fromString("30000004-328E-0FBB-C642-1AA6699BDADA");
private static final UUID PPOGATT_CHARACTERISTIC_WRITE = UUID.fromString("30000006-328E-0FBB-C642-1AA6699BDADA");
private BluetoothGattCharacteristic writeCharacteristics;
private final Context mContext;
private final PebbleLESupport mPebbleLESupport;
@ -58,9 +64,8 @@ class PebbleGATTClient extends BluetoothGattCallback {
PebbleGATTClient(PebbleLESupport pebbleLESupport, Context context, BluetoothDevice btDevice) {
mContext = context;
mBtDevice = btDevice;
mPebbleLESupport = pebbleLESupport;
connectToPebble(mBtDevice);
connectToPebble(btDevice);
}
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
@ -72,6 +77,8 @@ class PebbleGATTClient extends BluetoothGattCallback {
int newMTU = characteristic.getIntValue(FORMAT_UINT16, 0);
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));
}
@ -143,6 +150,12 @@ class PebbleGATTClient extends BluetoothGattCallback {
} else if (CHARACTERISTICUUID.equals(CONNECTIVITY_CHARACTERISTIC)) {
subscribeToMTU(gatt);
} else if (CHARACTERISTICUUID.equals(MTU_CHARACTERISTIC)) {
if (mPebbleLESupport.clientOnly) {
subscribeToPPoGATT(gatt);
} else {
setMTU(gatt);
}
} else if (CHARACTERISTICUUID.equals(PPOGATT_CHARACTERISTIC_READ)) {
setMTU(gatt);
}
}
@ -171,7 +184,11 @@ class PebbleGATTClient extends BluetoothGattCallback {
// 2 - always 0
// 3 - unknown, set on kitkat (seems to help to get a "better" pairing)
// 4 - unknown, set on some phones
characteristic.setValue(new byte[]{9});
if (mPebbleLESupport.clientOnly) {
characteristic.setValue(new byte[]{0x11}); // needed in clientOnly mode (TODO: try 0x19)
} else {
characteristic.setValue(new byte[]{0x09}); // I just keep this, because it worked
}
gatt.writeCharacteristic(characteristic);
} else {
LOG.info("This seems to be some <4.0 FW Pebble, reading pairing trigger");
@ -239,6 +256,25 @@ class PebbleGATTClient extends BluetoothGattCallback {
gatt.writeCharacteristic(characteristic);
}
private void subscribeToPPoGATT(BluetoothGatt gatt) {
LOG.info("subscribing to PPoGATT read characteristic");
BluetoothGattDescriptor descriptor = gatt.getService(PPOGATT_SERVICE_UUID).getCharacteristic(PPOGATT_CHARACTERISTIC_READ).getDescriptor(CHARACTERISTIC_CONFIGURATION_DESCRIPTOR);
descriptor.setValue(new byte[]{1, 0});
gatt.writeDescriptor(descriptor);
gatt.setCharacteristicNotification(gatt.getService(PPOGATT_SERVICE_UUID).getCharacteristic(PPOGATT_CHARACTERISTIC_READ), true);
writeCharacteristics = gatt.getService(PPOGATT_SERVICE_UUID).getCharacteristic(PPOGATT_CHARACTERISTIC_WRITE);
}
synchronized void sendDataToPebble(byte[] data) {
writeCharacteristics.setValue(data.clone());
mBluetoothGatt.writeCharacteristic(writeCharacteristics);
}
synchronized void sendAckToPebble(int serial) {
writeCharacteristics.setValue(new byte[]{(byte) (((serial << 3) | 1) & 0xff)});
mBluetoothGatt.writeCharacteristic(writeCharacteristics);
}
public void close() {
if (mBluetoothGatt != null) {
mBluetoothGatt.disconnect();

View File

@ -71,13 +71,12 @@ class PebbleGATTServer extends BluetoothGattServerCallback {
}
synchronized void sendDataToPebble(byte[] data) {
//LOG.info("send data to pebble " + GB.hexdump(data, 0, -1));
writeCharacteristics.setValue(data.clone());
mBluetoothGattServer.notifyCharacteristicChanged(mBtDevice, writeCharacteristics, false);
}
synchronized private void sendAckToPebble(int serial) {
synchronized void sendAckToPebble(int serial) {
writeCharacteristics.setValue(new byte[]{(byte) (((serial << 3) | 1) & 0xff)});
mBluetoothGattServer.notifyCharacteristicChanged(mBtDevice, writeCharacteristics, false);
@ -110,39 +109,7 @@ class PebbleGATTServer extends BluetoothGattServerCallback {
LOG.warn("unexpected write request");
return;
}
if (!mPebbleLESupport.mIsConnected) {
mPebbleLESupport.mIsConnected = true;
synchronized (mPebbleLESupport) {
mPebbleLESupport.notify();
}
}
//LOG.info("write request: offset = " + offset + " value = " + GB.hexdump(value, 0, -1));
int header = value[0] & 0xff;
int command = header & 7;
int serial = header >> 3;
if (command == 0x01) {
LOG.info("got ACK for serial = " + serial);
if (mPebbleLESupport.mPPAck != null) {
mPebbleLESupport.mPPAck.countDown();
} else {
LOG.warn("mPPAck countdownlatch is not present but it probably should");
}
}
if (command == 0x02) { // some request?
LOG.info("got command 0x02");
if (value.length > 1) {
sendDataToPebble(new byte[]{0x03, 0x19, 0x19}); // no we don't know what that means
mPebbleLESupport.createPipedInputReader(); // FIXME: maybe not here
} else {
sendDataToPebble(new byte[]{0x03}); // no we don't know what that means
}
} else if (command == 0) { // normal package
LOG.info("got PPoGATT package serial = " + serial + " sending ACK");
sendAckToPebble(serial);
mPebbleLESupport.writeToPipedOutputStream(value, 1, value.length - 1);
}
mPebbleLESupport.handlePPoGATTPacket(value);
}
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {

View File

@ -39,8 +39,9 @@ public class PebbleLESupport {
private PipedOutputStream mPipedOutputStream;
private int mMTU = 20;
private int mMTULimit = Integer.MAX_VALUE;
boolean mIsConnected = false;
CountDownLatch mPPAck;
public boolean clientOnly = false; // currently broken, and only possible for Pebble 2
private boolean mIsConnected = false;
private CountDownLatch mPPAck;
public PebbleLESupport(Context context, final BluetoothDevice btDevice, PipedInputStream pipedInputStream, PipedOutputStream pipedOutputStream) throws IOException {
mBtDevice = btDevice;
@ -56,8 +57,10 @@ public class PebbleLESupport {
mMTULimit = Math.max(mMTULimit, 20);
mMTULimit = Math.min(mMTULimit, 512);
mPebbleGATTServer = new PebbleGATTServer(this, context, mBtDevice);
if (mPebbleGATTServer.initialize()) {
if (!clientOnly) {
mPebbleGATTServer = new PebbleGATTServer(this, context, mBtDevice);
}
if (clientOnly || mPebbleGATTServer.initialize()) {
mPebbleGATTClient = new PebbleGATTClient(this, context, mBtDevice);
try {
synchronized (this) {
@ -73,11 +76,11 @@ public class PebbleLESupport {
throw new IOException("connection failed");
}
void writeToPipedOutputStream(byte[] value, int offset, int count) {
private void writeToPipedOutputStream(byte[] value, int offset, int count) {
try {
mPipedOutputStream.write(value, offset, count);
} catch (IOException e) {
LOG.warn("error writing to output stream");
LOG.warn("error writing to output stream", e);
}
}
@ -101,7 +104,7 @@ public class PebbleLESupport {
}
}
synchronized void createPipedInputReader() {
private synchronized void createPipedInputReader() {
if (mPipeReader == null) {
mPipeReader = new PipeReader();
}
@ -126,6 +129,58 @@ public class PebbleLESupport {
mMTU = Math.min(mtu, mMTULimit);
}
public void handlePPoGATTPacket(byte[] value) {
if (!mIsConnected) {
mIsConnected = true;
synchronized (this) {
this.notify();
}
}
//LOG.info("write request: offset = " + offset + " value = " + GB.hexdump(value, 0, -1));
int header = value[0] & 0xff;
int command = header & 7;
int serial = header >> 3;
if (command == 0x01) {
LOG.info("got ACK for serial = " + serial);
if (mPPAck != null) {
mPPAck.countDown();
} else {
LOG.warn("mPPAck countdownlatch is not present but it probably should");
}
}
if (command == 0x02) { // some request?
LOG.info("got command 0x02");
if (value.length > 1) {
sendDataToPebble(new byte[]{0x03, 0x19, 0x19}); // no we don't know what that means
createPipedInputReader(); // FIXME: maybe not here
} else {
sendDataToPebble(new byte[]{0x03}); // no we don't know what that means
}
} else if (command == 0) { // normal package
LOG.info("got PPoGATT package serial = " + serial + " sending ACK");
sendAckToPebble(serial);
writeToPipedOutputStream(value, 1, value.length - 1);
}
}
private void sendAckToPebble(int serial) {
if (mPebbleGATTServer != null) {
mPebbleGATTServer.sendAckToPebble(serial);
} else {
mPebbleGATTClient.sendAckToPebble(serial);
}
}
private void sendDataToPebble(byte[] bytes) {
if (mPebbleGATTServer != null) {
mPebbleGATTServer.sendDataToPebble(bytes);
} else {
mPebbleGATTClient.sendDataToPebble(bytes);
}
}
private class PipeReader extends Thread {
int mmSequence = 0;
@ -159,7 +214,7 @@ public class PebbleLESupport {
byte[] outBuf = new byte[chunkSize + 1];
outBuf[0] = (byte) ((mmSequence++ << 3) & 0xff);
System.arraycopy(buf, srcPos, outBuf, 1, chunkSize);
mPebbleGATTServer.sendDataToPebble(outBuf);
sendDataToPebble(outBuf);
srcPos += chunkSize;
payloadToSend -= chunkSize;
}