1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-28 21:06:50 +01:00

Xiaomi: add support for data uploading over SPP

This commit is contained in:
MrYoranimo 2024-01-04 00:14:28 +01:00 committed by José Rebelo
parent e5c2bd51c2
commit b31d98c7a0
4 changed files with 42 additions and 8 deletions

View File

@ -22,6 +22,8 @@ import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Context;
import android.widget.Toast;
import androidx.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -125,8 +127,6 @@ public class XiaomiBleSupport extends XiaomiConnectionSupport {
XiaomiBleSupport.this.characteristicDataUpload.setEncrypted(uuidSet.isEncrypted());
XiaomiBleSupport.this.characteristicDataUpload.setIncrementNonce(false);
mXiaomiSupport.getDataUploadService().setDataUploadCharacteristic(XiaomiBleSupport.this.characteristicDataUpload);
builder.requestMtu(247);
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
builder.notify(btCharacteristicCommandWrite, true);
@ -207,6 +207,16 @@ public class XiaomiBleSupport extends XiaomiConnectionSupport {
this.characteristicCommandWrite.write(taskName, command.toByteArray());
}
@Override
public void sendDataChunk(String taskName, byte[] chunk, @Nullable XiaomiCharacteristic.SendCallback callback) {
if (this.characteristicDataUpload == null) {
LOG.warn("characteristicDataUpload is null!");
return;
}
this.characteristicDataUpload.write(taskName, chunk, callback);
}
/**
* Realistically, this function should only be used during auth, as we must schedule the command after
* notifications were enabled on the characteristics, and for that we need the builder to guarantee the

View File

@ -19,6 +19,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import androidx.annotation.Nullable;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.proto.xiaomi.XiaomiProto;
@ -30,4 +32,5 @@ public abstract class XiaomiConnectionSupport {
public abstract void setContext(final GBDevice device, final BluetoothAdapter adapter, final Context context);
public abstract void disconnect();
public abstract void sendCommand(final String taskName, final XiaomiProto.Command command);
public abstract void sendDataChunk(final String taskName, final byte[] chunk, @Nullable final XiaomiCharacteristic.SendCallback callback);
}

View File

@ -17,12 +17,17 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiSppPacket.CHANNEL_FITNESS;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiSppPacket.CHANNEL_MASS;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiSppPacket.CHANNEL_PROTO_RX;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiSppPacket.DATA_TYPE_ENCRYPTED;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiSppPacket.PACKET_PREAMBLE;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import androidx.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -258,4 +263,25 @@ public class XiaomiSppSupport extends XiaomiConnectionSupport {
builder.write(packet.encode(mXiaomiSupport.getAuthService(), encryptionCounter));
// do not queue here, that's the job of the caller
}
public void sendDataChunk(final String taskName, final byte[] chunk, @Nullable final XiaomiCharacteristic.SendCallback callback) {
XiaomiSppPacket packet = XiaomiSppPacket.newBuilder()
.channel(CHANNEL_MASS)
.needsResponse(false)
.flag(true)
.opCode(2)
.frameSerial(frameCounter.getAndIncrement())
.dataType(DATA_TYPE_ENCRYPTED)
.payload(chunk)
.build();
LOG.debug("sending data packet: {}", packet);
TransactionBuilder b = this.commsSupport.createTransactionBuilder("send " + taskName);
b.write(packet.encode(mXiaomiSupport.getAuthService(), encryptionCounter));
b.queue(commsSupport.getQueue());
if (callback != null) {
// callback puts a SetProgressAction onto the queue
callback.onSend();
}
}
}

View File

@ -44,7 +44,6 @@ public class XiaomiDataUploadService extends AbstractXiaomiService {
public static final byte TYPE_FIRMWARE = 32;
public static final byte TYPE_NOTIFICATION_ICON = 50;
private XiaomiCharacteristic characteristic;
private Callback callback;
private byte currentType;
@ -153,7 +152,7 @@ public class XiaomiDataUploadService extends AbstractXiaomiService {
BLETypeConversions.writeUint16(chunkToSend, 2, currentPart);
System.arraycopy(payload, startIndex, chunkToSend, 4, endIndex - startIndex);
characteristic.write("upload part " + currentPart + " of " + totalParts, chunkToSend, new XiaomiCharacteristic.SendCallback() {
getSupport().getConnectionSpecificSupport().sendDataChunk("upload part " + currentPart + " of " + totalParts, chunkToSend, new XiaomiCharacteristic.SendCallback() {
@Override
public void onSend() {
final int progressPercent = Math.round((100.0f * currentPart) / totalParts);
@ -175,10 +174,6 @@ public class XiaomiDataUploadService extends AbstractXiaomiService {
}
}
public void setDataUploadCharacteristic(final XiaomiCharacteristic characteristic) {
this.characteristic = characteristic;
}
private void onUploadFinish(final boolean success) {
this.currentType = 0;
this.currentBytes = null;