mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-01 07:02:57 +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;
|
private int currentLength;
|
||||||
ByteBuffer reassemblyBuffer;
|
ByteBuffer reassemblyBuffer;
|
||||||
|
|
||||||
|
// Keep track of last handle and count for acks
|
||||||
|
private byte lastHandle;
|
||||||
|
private byte lastCount;
|
||||||
|
|
||||||
private volatile byte[] sharedSessionKey;
|
private volatile byte[] sharedSessionKey;
|
||||||
|
|
||||||
private Huami2021Handler huami2021Handler;
|
private Huami2021Handler huami2021Handler;
|
||||||
@ -52,16 +56,25 @@ public class Huami2021ChunkedDecoder {
|
|||||||
this.huami2021Handler = huami2021Handler;
|
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;
|
int i = 0;
|
||||||
if (data[i++] != 0x03) {
|
if (data[i++] != 0x03) {
|
||||||
//LOG.warn("Ignoring non-chunked payload");
|
LOG.warn("Ignoring non-chunked payload");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
final byte flags = data[i++];
|
final byte flags = data[i++];
|
||||||
final boolean encrypted = ((flags & 0x08) == 0x08);
|
final boolean encrypted = ((flags & 0x08) == 0x08);
|
||||||
final boolean firstChunk = ((flags & 0x01) == 0x01);
|
final boolean firstChunk = ((flags & 0x01) == 0x01);
|
||||||
final boolean lastChunk = ((flags & 0x02) == 0x02);
|
final boolean lastChunk = ((flags & 0x02) == 0x02);
|
||||||
|
final boolean needsAck = ((flags & 0x04) == 0x04);
|
||||||
|
|
||||||
if (force2021Protocol) {
|
if (force2021Protocol) {
|
||||||
i++; // skip extended header
|
i++; // skip extended header
|
||||||
@ -69,9 +82,10 @@ public class Huami2021ChunkedDecoder {
|
|||||||
final byte handle = data[i++];
|
final byte handle = data[i++];
|
||||||
if (currentHandle != null && currentHandle != handle) {
|
if (currentHandle != null && currentHandle != handle) {
|
||||||
LOG.warn("ignoring handle {}, expected {}", handle, currentHandle);
|
LOG.warn("ignoring handle {}, expected {}", handle, currentHandle);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
byte count = data[i++];
|
lastHandle = handle;
|
||||||
|
lastCount = data[i++];
|
||||||
if (firstChunk) { // beginning
|
if (firstChunk) { // beginning
|
||||||
int full_length = (data[i++] & 0xff) | ((data[i++] & 0xff) << 8) | ((data[i++] & 0xff) << 16) | ((data[i++] & 0xff) << 24);
|
int full_length = (data[i++] & 0xff) | ((data[i++] & 0xff) << 8) | ((data[i++] & 0xff) << 16) | ((data[i++] & 0xff) << 24);
|
||||||
currentLength = full_length;
|
currentLength = full_length;
|
||||||
@ -96,7 +110,7 @@ public class Huami2021ChunkedDecoder {
|
|||||||
LOG.warn("Got encrypted message, but there's no shared session key");
|
LOG.warn("Got encrypted message, but there's no shared session key");
|
||||||
currentHandle = null;
|
currentHandle = null;
|
||||||
currentType = 0;
|
currentType = 0;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] messagekey = new byte[16];
|
byte[] messagekey = new byte[16];
|
||||||
@ -110,7 +124,7 @@ public class Huami2021ChunkedDecoder {
|
|||||||
LOG.warn("error decrypting " + e);
|
LOG.warn("error decrypting " + e);
|
||||||
currentHandle = null;
|
currentHandle = null;
|
||||||
currentType = 0;
|
currentType = 0;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
@ -128,5 +142,7 @@ public class Huami2021ChunkedDecoder {
|
|||||||
currentHandle = null;
|
currentHandle = null;
|
||||||
currentType = 0;
|
currentType = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return needsAck;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2293,8 +2293,8 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
|||||||
} else if (HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION.equals(characteristicUUID)) {
|
} else if (HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION.equals(characteristicUUID)) {
|
||||||
handleConfigurationInfo(characteristic.getValue());
|
handleConfigurationInfo(characteristic.getValue());
|
||||||
return true;
|
return true;
|
||||||
} else if (HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ.equals(characteristicUUID) && huami2021ChunkedDecoder != null) {
|
} else if (HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ.equals(characteristicUUID)) {
|
||||||
huami2021ChunkedDecoder.decode(characteristic.getValue());
|
handleChunked(characteristic.getValue());
|
||||||
return true;
|
return true;
|
||||||
} else if (HuamiService.UUID_CHARACTERISTIC_RAW_SENSOR_DATA.equals(characteristicUUID)) {
|
} else if (HuamiService.UUID_CHARACTERISTIC_RAW_SENSOR_DATA.equals(characteristicUUID)) {
|
||||||
handleRawSensorData(characteristic.getValue());
|
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) {
|
private void decodeAndUpdateAlarmStatus(byte[] response, boolean withTimes) {
|
||||||
List<nodomain.freeyourgadget.gadgetbridge.entities.Alarm> alarms = DBHelper.getAlarms(gbDevice);
|
List<nodomain.freeyourgadget.gadgetbridge.entities.Alarm> alarms = DBHelper.getAlarms(gbDevice);
|
||||||
int maxAlarms = 10;
|
int maxAlarms = 10;
|
||||||
|
@ -127,7 +127,11 @@ public class InitOperation2021 extends InitOperation implements Huami2021Handler
|
|||||||
return super.onCharacteristicChanged(gatt, characteristic);
|
return super.onCharacteristicChanged(gatt, characteristic);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.huami2021ChunkedDecoder.decode(value);
|
final boolean needsAck = huami2021ChunkedDecoder.decode(value);
|
||||||
|
if (needsAck) {
|
||||||
|
huamiSupport.sendChunkedAck();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user