Zepp OS: Improve firmware upgrades

This commit is contained in:
José Rebelo 2022-09-25 22:59:09 +01:00 committed by Gitea
parent e6411b15ab
commit cadcfb787a
4 changed files with 113 additions and 27 deletions

View File

@ -25,11 +25,13 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@ -83,9 +85,7 @@ public abstract class Huami2021FirmwareInfo extends AbstractHuamiFirmwareInfo {
final byte[] firmwareBin = getFileFromZip(uihhFirmwareZipFile.getContent(), "META/firmware.bin");
if (isCompatibleFirmwareBin(firmwareBin)) {
// TODO: Firmware upgrades with UIHH files are untested, so they are disabled
return HuamiFirmwareType.INVALID;
//return HuamiFirmwareType.FIRMWARE_UIHH_2021_ZIP_WITH_CHANGELOG;
return HuamiFirmwareType.FIRMWARE_UIHH_2021_ZIP_WITH_CHANGELOG;
}
}
@ -147,6 +147,34 @@ public abstract class Huami2021FirmwareInfo extends AbstractHuamiFirmwareInfo {
return null;
}
public Huami2021FirmwareInfo repackFirmwareInUIHH() throws IOException {
if (!firmwareType.equals(HuamiFirmwareType.FIRMWARE)) {
throw new IllegalStateException("Can only repack FIRMWARE");
}
final UIHHContainer uihh = packFirmwareInUIHH();
try {
final Constructor<? extends Huami2021FirmwareInfo> constructor = this.getClass().getConstructor(byte[].class);
return constructor.newInstance((Object) uihh.toRawBytes());
} catch (final Exception e) {
throw new IOException("Failed to construct new " + getClass().getName(), e);
}
}
private UIHHContainer packFirmwareInUIHH() {
final UIHHContainer uihh = new UIHHContainer();
final byte[] timestampBytes = BLETypeConversions.fromUint32((int) (System.currentTimeMillis() / 1000L));
final String changelogText = "Unknown changelog";
final byte[] changelogBytes = BLETypeConversions.join(
timestampBytes,
changelogText.getBytes(StandardCharsets.UTF_8)
);
uihh.addFile(UIHHContainer.FileType.FIRMWARE_ZIP, getBytes());
uihh.addFile(UIHHContainer.FileType.FIRMWARE_CHANGELOG, changelogBytes);
return uihh;
}
private boolean isCompatibleFirmwareBin(final byte[] firmwareBin) {
if (firmwareBin == null) {
return false;

View File

@ -33,6 +33,7 @@ public class MiBand7FirmwareInfo extends Huami2021FirmwareInfo {
private static final Map<Integer, String> crcToVersion = new HashMap<Integer, String>() {{
// firmware
put(26036, "1.20.3.1");
put(55449, "1.27.0.4");
}};
public MiBand7FirmwareInfo(final byte[] bytes) {

View File

@ -150,30 +150,7 @@ public class UpdateFirmwareOperation2020 extends UpdateFirmwareOperation {
builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.updating_firmware), getContext()));
int fwSize = getFirmwareInfo().getSize();
byte[] sizeBytes = BLETypeConversions.fromUint32(fwSize);
int crc32 = firmwareInfo.getCrc32();
byte[] chunkSizeBytes = BLETypeConversions.fromUint16(mChunkLength);
byte[] crcBytes = BLETypeConversions.fromUint32(crc32);
byte[] bytes = new byte[]{
COMMAND_SEND_FIRMWARE_INFO,
getFirmwareInfo().getFirmwareType().getValue(),
sizeBytes[0],
sizeBytes[1],
sizeBytes[2],
sizeBytes[3],
crcBytes[0],
crcBytes[1],
crcBytes[2],
crcBytes[3],
chunkSizeBytes[0],
chunkSizeBytes[1],
0, // ??
0, // index
1, // count
sizeBytes[0], // total size? right now it is equal to the size above
sizeBytes[1],
sizeBytes[2],
sizeBytes[3]
};
byte[] bytes = buildFirmwareInfoCommand();
if (getFirmwareInfo().getFirmwareType() == HuamiFirmwareType.WATCHFACE) {
byte[] fwBytes = firmwareInfo.getBytes();
@ -200,6 +177,34 @@ public class UpdateFirmwareOperation2020 extends UpdateFirmwareOperation {
}
}
protected byte[] buildFirmwareInfoCommand() {
int fwSize = getFirmwareInfo().getSize();
byte[] sizeBytes = BLETypeConversions.fromUint32(fwSize);
int crc32 = firmwareInfo.getCrc32();
byte[] chunkSizeBytes = BLETypeConversions.fromUint16(mChunkLength);
byte[] crcBytes = BLETypeConversions.fromUint32(crc32);
return new byte[]{
COMMAND_SEND_FIRMWARE_INFO,
getFirmwareInfo().getFirmwareType().getValue(),
sizeBytes[0],
sizeBytes[1],
sizeBytes[2],
sizeBytes[3],
crcBytes[0],
crcBytes[1],
crcBytes[2],
crcBytes[3],
chunkSizeBytes[0],
chunkSizeBytes[1],
0, // 0 to update in foreground, 1 for background
0, // index
1, // count
sizeBytes[0], // total size? right now it is equal to the size above
sizeBytes[1],
sizeBytes[2],
sizeBytes[3]
};
}
public boolean requestParameters() {
try {

View File

@ -16,6 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations;
import android.content.Context;
import android.net.Uri;
import org.slf4j.Logger;
@ -24,7 +25,9 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.AbstractHuamiFirmwareInfo;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiFirmwareType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport;
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
@ -42,6 +45,28 @@ public class UpdateFirmwareOperation2021 extends UpdateFirmwareOperation2020 {
builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ), enable);
}
@Override
AbstractHuamiFirmwareInfo createFwInfo(final Uri uri, final Context context) throws IOException {
return super.createFwInfo(uri, context);
/* This does not actually seem to be needed, but it's what the official app does
final HuamiFWHelper fwHelper = getSupport().createFWHelper(uri, context);
final AbstractHuamiFirmwareInfo firmwareInfo = fwHelper.getFirmwareInfo();
if (!(firmwareInfo instanceof Huami2021FirmwareInfo)) {
throw new IllegalArgumentException("Firmware not Huami2021FirmwareInfo");
}
final Huami2021FirmwareInfo firmwareInfo2021 = (Huami2021FirmwareInfo) firmwareInfo;
if (firmwareInfo2021.getFirmwareType() == HuamiFirmwareType.FIRMWARE) {
// This does not actually seem to be needed, but it's what the official app does
return firmwareInfo2021.repackFirmwareInUIHH();
}
return firmwareInfo;
*/
}
@Override
protected void handleNotificationNotif(byte[] value) {
super.handleNotificationNotif(value);
@ -59,4 +84,31 @@ public class UpdateFirmwareOperation2021 extends UpdateFirmwareOperation2020 {
}
}
}
@Override
protected byte[] buildFirmwareInfoCommand() {
final int fwSize = firmwareInfo.getSize();
final int crc32 = firmwareInfo.getCrc32();
final byte[] sizeBytes = BLETypeConversions.fromUint32(fwSize);
final byte[] chunkSizeBytes = BLETypeConversions.fromUint16(mChunkLength);
final byte[] crcBytes = BLETypeConversions.fromUint32(crc32);
return new byte[]{
COMMAND_SEND_FIRMWARE_INFO,
getFirmwareInfo().getFirmwareType().getValue(),
sizeBytes[0],
sizeBytes[1],
sizeBytes[2],
sizeBytes[3],
crcBytes[0],
crcBytes[1],
crcBytes[2],
crcBytes[3],
chunkSizeBytes[0],
chunkSizeBytes[1],
0, // 0 to update in foreground, 1 for background
(byte) 0xff, // ??
};
}
}