mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-25 19:36:50 +01:00
Huami 2021: Handle chunked ACKs
This commit is contained in:
parent
4e9d883ae2
commit
74dac3f5cd
@ -33,6 +33,10 @@ public class Huami2021ChunkedDecoder {
|
||||
private int currentLength;
|
||||
ByteBuffer reassemblyBuffer;
|
||||
|
||||
// Keep track of last handle and count for acks
|
||||
private byte lastHandle;
|
||||
private byte lastCount;
|
||||
|
||||
private volatile byte[] sharedSessionKey;
|
||||
|
||||
private Huami2021Handler huami2021Handler;
|
||||
@ -52,16 +56,25 @@ public class Huami2021ChunkedDecoder {
|
||||
this.huami2021Handler = huami2021Handler;
|
||||
}
|
||||
|
||||
public void decode(final byte[] data) {
|
||||
public byte getLastHandle() {
|
||||
return lastHandle;
|
||||
}
|
||||
|
||||
public byte getLastCount() {
|
||||
return lastCount;
|
||||
}
|
||||
|
||||
public boolean decode(final byte[] data) {
|
||||
int i = 0;
|
||||
if (data[i++] != 0x03) {
|
||||
//LOG.warn("Ignoring non-chunked payload");
|
||||
return;
|
||||
LOG.warn("Ignoring non-chunked payload");
|
||||
return false;
|
||||
}
|
||||
final byte flags = data[i++];
|
||||
final boolean encrypted = ((flags & 0x08) == 0x08);
|
||||
final boolean firstChunk = ((flags & 0x01) == 0x01);
|
||||
final boolean lastChunk = ((flags & 0x02) == 0x02);
|
||||
final boolean needsAck = ((flags & 0x04) == 0x04);
|
||||
|
||||
if (force2021Protocol) {
|
||||
i++; // skip extended header
|
||||
@ -69,9 +82,10 @@ public class Huami2021ChunkedDecoder {
|
||||
final byte handle = data[i++];
|
||||
if (currentHandle != null && currentHandle != handle) {
|
||||
LOG.warn("ignoring handle {}, expected {}", handle, currentHandle);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
byte count = data[i++];
|
||||
lastHandle = handle;
|
||||
lastCount = data[i++];
|
||||
if (firstChunk) { // beginning
|
||||
int full_length = (data[i++] & 0xff) | ((data[i++] & 0xff) << 8) | ((data[i++] & 0xff) << 16) | ((data[i++] & 0xff) << 24);
|
||||
currentLength = full_length;
|
||||
@ -96,7 +110,7 @@ public class Huami2021ChunkedDecoder {
|
||||
LOG.warn("Got encrypted message, but there's no shared session key");
|
||||
currentHandle = null;
|
||||
currentType = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] messagekey = new byte[16];
|
||||
@ -110,7 +124,7 @@ public class Huami2021ChunkedDecoder {
|
||||
LOG.warn("error decrypting " + e);
|
||||
currentHandle = null;
|
||||
currentType = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
LOG.debug(
|
||||
@ -128,5 +142,7 @@ public class Huami2021ChunkedDecoder {
|
||||
currentHandle = null;
|
||||
currentType = 0;
|
||||
}
|
||||
|
||||
return needsAck;
|
||||
}
|
||||
}
|
||||
|
@ -2293,8 +2293,8 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
||||
} else if (HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION.equals(characteristicUUID)) {
|
||||
handleConfigurationInfo(characteristic.getValue());
|
||||
return true;
|
||||
} else if (HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ.equals(characteristicUUID) && huami2021ChunkedDecoder != null) {
|
||||
huami2021ChunkedDecoder.decode(characteristic.getValue());
|
||||
} else if (HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ.equals(characteristicUUID)) {
|
||||
handleChunked(characteristic.getValue());
|
||||
return true;
|
||||
} else if (HuamiService.UUID_CHARACTERISTIC_RAW_SENSOR_DATA.equals(characteristicUUID)) {
|
||||
handleRawSensorData(characteristic.getValue());
|
||||
@ -2455,6 +2455,47 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
||||
}
|
||||
}
|
||||
|
||||
private void handleChunked(final byte[] value) {
|
||||
switch (value[0]) {
|
||||
case 0x03:
|
||||
if (huami2021ChunkedDecoder != null) {
|
||||
final boolean needsAck = huami2021ChunkedDecoder.decode(value);
|
||||
if (needsAck) {
|
||||
sendChunkedAck();
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Got chunked payload, but decoder is null");
|
||||
}
|
||||
return;
|
||||
case 0x04:
|
||||
final byte handle = value[2];
|
||||
final byte count = value[4];
|
||||
LOG.info("Got chunked ack, handle={}, count={}", handle, count);
|
||||
// TODO: We should probably update the handle and count on the encoder
|
||||
return;
|
||||
default:
|
||||
LOG.warn("Unhandled chunked payload of type {}", value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendChunkedAck() {
|
||||
if (characteristicChunked2021Read == null) {
|
||||
LOG.error("Chunked read characteristic is null, can't send ack");
|
||||
return;
|
||||
}
|
||||
|
||||
final byte handle = huami2021ChunkedDecoder.getLastHandle();
|
||||
final byte count = huami2021ChunkedDecoder.getLastCount();
|
||||
|
||||
try {
|
||||
final TransactionBuilder builder = performInitialized("send chunked ack");
|
||||
builder.write(characteristicChunked2021Read, new byte[] {0x04, 0x00, handle, 0x01, count});
|
||||
builder.queue(getQueue());
|
||||
} catch (final Exception e) {
|
||||
LOG.error("Failed to send chunked ack", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void decodeAndUpdateAlarmStatus(byte[] response, boolean withTimes) {
|
||||
List<nodomain.freeyourgadget.gadgetbridge.entities.Alarm> alarms = DBHelper.getAlarms(gbDevice);
|
||||
int maxAlarms = 10;
|
||||
|
@ -127,7 +127,11 @@ public class InitOperation2021 extends InitOperation implements Huami2021Handler
|
||||
return super.onCharacteristicChanged(gatt, characteristic);
|
||||
}
|
||||
|
||||
this.huami2021ChunkedDecoder.decode(value);
|
||||
final boolean needsAck = huami2021ChunkedDecoder.decode(value);
|
||||
if (needsAck) {
|
||||
huamiSupport.sendChunkedAck();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user