mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 21:06:50 +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:
parent
bd012cab2a
commit
f6131772d6
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
if (!clientOnly) {
|
||||
mPebbleGATTServer = new PebbleGATTServer(this, context, mBtDevice);
|
||||
if (mPebbleGATTServer.initialize()) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user