/* Copyright (C) 2019-2024 Daniel Dakhno
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.UUID;
import java.util.zip.CRC32;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.Request;
public class UploadFileRequest extends Request {
public enum UploadState{INITIALIZED, UPLOAD, UPLOADED, ERROR}
public UploadState state;
public ArrayList packets = new ArrayList<>();
public UploadFileRequest(short handle, byte[] file) {
int fileLength = file.length + 4;
ByteBuffer buffer = this.createBuffer();
buffer.putShort(1, handle);
buffer.putInt(3, 0);
buffer.putInt(7, fileLength);
buffer.putInt(11, fileLength);
this.data = buffer.array();
prepareFilePackets(file);
state = UploadState.INITIALIZED;
}
@Override
public void handleResponse(BluetoothGattCharacteristic characteristic) {
byte[] value = characteristic.getValue();
if (value.length == 4) {
if (value[1] != 0) {
state = UploadState.ERROR;
return;
}
state = UploadState.UPLOAD;
}else if(value.length == 9){
if(value[1] != 0){
state = UploadState.ERROR;
return;
}
state = UploadState.UPLOADED;
}
}
private void prepareFilePackets(byte[] file) {
ByteBuffer buffer = ByteBuffer.allocate(file.length + 4);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.put(file);
CRC32 crc = new CRC32();
crc.update(file);
buffer.putInt((int) crc.getValue());
byte[] fileFull = buffer.array();
for (int i = 0, sequence = 0; i < fileFull.length + 4; i += 18, sequence++) {
byte[] packet;
if (i + 18 >= fileFull.length) {
packet = new byte[fileFull.length - i + 2];
System.arraycopy(fileFull, i, packet, 2, fileFull.length - i);
} else {
packet = new byte[20];
System.arraycopy(fileFull, i, packet, 2, 18);
}
packet[0] = 0x12;
packet[1] = (byte) sequence;
packets.add(packet);
}
packets.get(0)[1] |= 0x40;
if (packets.size() > 1) {
packets.get(packets.size() - 1)[1] |= 0x80;
}
}
@Override
public byte[] getStartSequence() {
return new byte[]{17};
}
@Override
public int getPayloadLength() {
return 15;
}
@Override
public UUID getRequestUUID() {
return UUID.fromString("3dda0007-957f-7d4a-34a6-74696673696d");
}
}