mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-24 19:06:53 +01:00
Enhanced support for firmware detection, recognition and upgrade #234
Also supports double firmware upgrade for Mi1S. - so far, only hr firmware upgrade is tested for 1S - adds junit testcases for firmware recognition and handling
This commit is contained in:
parent
6d8d6d5bc8
commit
4f956000c5
@ -3,6 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.devices.miband;
|
|||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -10,27 +11,23 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.Mi1SInfo;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.AbstractMiFirmwareInfo;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Also see Mi1SInfo.
|
* Also see Mi1SFirmwareInfo.
|
||||||
*/
|
*/
|
||||||
public class MiBandFWHelper {
|
public class MiBandFWHelper {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(MiBandFWHelper.class);
|
private static final Logger LOG = LoggerFactory.getLogger(MiBandFWHelper.class);
|
||||||
private static final int MI_FW_BASE_OFFSET = 1056;
|
|
||||||
private static final int MI1S_FW_BASE_OFFSET = 1092;
|
|
||||||
|
|
||||||
private final Uri uri;
|
private final Uri uri;
|
||||||
private final ContentResolver cr;
|
private final ContentResolver cr;
|
||||||
private byte[] fw;
|
private final @NonNull AbstractMiFirmwareInfo firmwareInfo;
|
||||||
|
private final @NonNull byte[] fw;
|
||||||
private int baseOffset = -1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a different notification API which is also used on Mi1A devices.
|
* Provides a different notification API which is also used on Mi1A devices.
|
||||||
@ -56,7 +53,6 @@ public class MiBandFWHelper {
|
|||||||
throw new IOException("No content resolver");
|
throw new IOException("No content resolver");
|
||||||
}
|
}
|
||||||
|
|
||||||
baseOffset = determineBaseOffset(uri);
|
|
||||||
String pebblePattern = ".*\\.(pbw|pbz|pbl)";
|
String pebblePattern = ".*\\.(pbw|pbz|pbl)";
|
||||||
|
|
||||||
if (uri.getPath().matches(pebblePattern)) {
|
if (uri.getPath().matches(pebblePattern)) {
|
||||||
@ -65,62 +61,23 @@ public class MiBandFWHelper {
|
|||||||
|
|
||||||
try (InputStream in = new BufferedInputStream(cr.openInputStream(uri))) {
|
try (InputStream in = new BufferedInputStream(cr.openInputStream(uri))) {
|
||||||
this.fw = FileUtils.readAll(in, 1024 * 1024); // 1 MB
|
this.fw = FileUtils.readAll(in, 1024 * 1024); // 1 MB
|
||||||
if (fw.length <= getOffsetFirmwareVersionMajor()) {
|
this.firmwareInfo = determineFirmwareInfoFor(fw);
|
||||||
throw new IOException("This doesn't seem to be a Mi Band firmware, file size too small.");
|
|
||||||
}
|
|
||||||
byte firmwareVersionMajor = fw[getOffsetFirmwareVersionMajor()];
|
|
||||||
if (!isSupportedFirmwareVersionMajor(firmwareVersionMajor)) {
|
|
||||||
throw new IOException("Firmware major version not supported, either too new or this isn't a Mi Band firmware: " + firmwareVersionMajor);
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw ex; // pass through
|
throw ex; // pass through
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
throw new IOException("This doesn't seem to be a Mi Band firmware: " + ex.getLocalizedMessage(), ex);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IOException("Error reading firmware file: " + uri.toString(), e);
|
throw new IOException("Error reading firmware file: " + uri.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getOffsetFirmwareVersionMajor() {
|
|
||||||
return baseOffset + 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getOffsetFirmwareVersionMinor() {
|
|
||||||
return baseOffset + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getOffsetFirmwareVersionRevision() {
|
|
||||||
return baseOffset + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getOffsetFirmwareVersionBuild() {
|
|
||||||
return baseOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int determineBaseOffset(Uri uri) throws IOException {
|
|
||||||
String name = uri.getLastPathSegment().toLowerCase();
|
|
||||||
if (name.startsWith("mili")) {
|
|
||||||
if (name.contains("_hr")) {
|
|
||||||
return MI1S_FW_BASE_OFFSET;
|
|
||||||
}
|
|
||||||
return MI_FW_BASE_OFFSET;
|
|
||||||
} else {
|
|
||||||
throw new IOException("Unknown file name " + name + "; cannot recognize firmware by it.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte getFirmwareVersionMajor() {
|
|
||||||
return fw[getOffsetFirmwareVersionMajor()];
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte getFirmwareVersionMinor() {
|
|
||||||
return fw[getOffsetFirmwareVersionMinor()];
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isSupportedFirmwareVersionMajor(byte firmwareVersionMajor) {
|
|
||||||
return firmwareVersionMajor == 1 || firmwareVersionMajor == 4 || firmwareVersionMajor == 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getFirmwareVersion() {
|
public int getFirmwareVersion() {
|
||||||
return (fw[getOffsetFirmwareVersionMajor()] << 24) | (fw[getOffsetFirmwareVersionMinor()] << 16) | (fw[getOffsetFirmwareVersionRevision()] << 8) | fw[getOffsetFirmwareVersionBuild()];
|
// FIXME: UnsupportedOperationException!
|
||||||
|
return firmwareInfo.getFirst().getFirmwareVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFirmware2Version() {
|
||||||
|
return firmwareInfo.getFirst().getFirmwareVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String formatFirmwareVersion(int version) {
|
public static String formatFirmwareVersion(int version) {
|
||||||
@ -135,11 +92,11 @@ public class MiBandFWHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getHumanFirmwareVersion() {
|
public String getHumanFirmwareVersion() {
|
||||||
return String.format(Locale.US, "%d.%d.%d.%d", fw[getOffsetFirmwareVersionMajor()], fw[getOffsetFirmwareVersionMinor()], fw[getOffsetFirmwareVersionRevision()], fw[getOffsetFirmwareVersionBuild()]);
|
return format(getFirmwareVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHumanFirmwareVersion2() {
|
public String getHumanFirmwareVersion2() {
|
||||||
return format(Mi1SInfo.getFirmware2VersionFrom(getFw()));
|
return format(firmwareInfo.getSecond().getFirmwareVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String format(int version) {
|
public String format(int version) {
|
||||||
@ -160,20 +117,24 @@ public class MiBandFWHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFirmwareGenerallyCompatibleWith(GBDevice device) {
|
public boolean isFirmwareGenerallyCompatibleWith(GBDevice device) {
|
||||||
String deviceHW = device.getHardwareVersion();
|
return firmwareInfo.isGenerallyCompatibleWith(device);
|
||||||
if (MiBandConst.MI_1.equals(deviceHW)) {
|
|
||||||
return getFirmwareVersionMajor() == 1;
|
|
||||||
}
|
|
||||||
if (MiBandConst.MI_1A.equals(deviceHW)) {
|
|
||||||
return getFirmwareVersionMajor() == 5;
|
|
||||||
}
|
|
||||||
if (MiBandConst.MI_1S.equals(deviceHW)) {
|
|
||||||
return getFirmwareVersionMajor() == 4;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSingleFirmware() {
|
public boolean isSingleFirmware() {
|
||||||
return Mi1SInfo.isSingleMiBandFirmware(getFw());
|
return firmwareInfo.isSingleMiBandFirmware();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param wholeFirmwareBytes
|
||||||
|
* @return
|
||||||
|
* @throws IllegalArgumentException when the data is not recognized as firmware data
|
||||||
|
*/
|
||||||
|
public static @NonNull AbstractMiFirmwareInfo determineFirmwareInfoFor(byte[] wholeFirmwareBytes) {
|
||||||
|
return AbstractMiFirmwareInfo.determineFirmwareInfoFor(wholeFirmwareBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractMiFirmwareInfo getFirmwareInfo() {
|
||||||
|
return firmwareInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ public class UserInfo {
|
|||||||
sequence[8] = (byte) (type & 0xff);
|
sequence[8] = (byte) (type & 0xff);
|
||||||
|
|
||||||
int aliasFrom = 9;
|
int aliasFrom = 9;
|
||||||
if (mDeviceInfo.isMili1A() || mDeviceInfo.isMilli1S()) {
|
if (mDeviceInfo.isMili1A() || mDeviceInfo.isMili1S()) {
|
||||||
sequence[9] = (byte) (mDeviceInfo.feature & 255);
|
sequence[9] = (byte) (mDeviceInfo.feature & 255);
|
||||||
sequence[10] = (byte) (mDeviceInfo.appearance & 255);
|
sequence[10] = (byte) (mDeviceInfo.appearance & 255);
|
||||||
aliasFrom = 11;
|
aliasFrom = 11;
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some helper methods for Mi1 and Mi1A firmware.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractMi1FirmwareInfo extends AbstractMiFirmwareInfo {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(AbstractMi1FirmwareInfo.class);
|
||||||
|
|
||||||
|
private static final int MI1_FW_BASE_OFFSET = 1056;
|
||||||
|
|
||||||
|
protected AbstractMi1FirmwareInfo(@NonNull byte[] wholeFirmwareBytes) {
|
||||||
|
super(wholeFirmwareBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirmwareOffset()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFirmwareLength()
|
||||||
|
{
|
||||||
|
return wholeFirmwareBytes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFirmwareVersion()
|
||||||
|
{
|
||||||
|
return (wholeFirmwareBytes[getOffsetFirmwareVersionMajor()] << 24)
|
||||||
|
| (wholeFirmwareBytes[getOffsetFirmwareVersionMinor()] << 16)
|
||||||
|
| (wholeFirmwareBytes[getOffsetFirmwareVersionRevision()] << 8)
|
||||||
|
| wholeFirmwareBytes[getOffsetFirmwareVersionBuild()];
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getOffsetFirmwareVersionMajor() {
|
||||||
|
return MI1_FW_BASE_OFFSET + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getOffsetFirmwareVersionMinor() {
|
||||||
|
return MI1_FW_BASE_OFFSET + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getOffsetFirmwareVersionRevision() {
|
||||||
|
return MI1_FW_BASE_OFFSET + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getOffsetFirmwareVersionBuild() {
|
||||||
|
return MI1_FW_BASE_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isGenerallySupportedFirmware() {
|
||||||
|
if (!isSingleMiBandFirmware()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int majorVersion = getFirmwareVersionMajor();
|
||||||
|
return majorVersion == getSupportedMajorVersion();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return false;
|
||||||
|
} catch (IndexOutOfBoundsException ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int getSupportedMajorVersion();
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
|
||||||
|
public abstract class AbstractMi1SFirmwareInfo extends AbstractMiFirmwareInfo {
|
||||||
|
|
||||||
|
public AbstractMi1SFirmwareInfo(@NonNull byte[] wholeFirmwareBytes) {
|
||||||
|
super(wholeFirmwareBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGenerallyCompatibleWith(GBDevice device) {
|
||||||
|
return MiBandConst.MI_1S.equals(device.getHardwareVersion());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
|
||||||
|
public abstract class AbstractMiFirmwareInfo {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param wholeFirmwareBytes
|
||||||
|
* @return
|
||||||
|
* @throws IllegalArgumentException when the data is not recognized as firmware data
|
||||||
|
*/
|
||||||
|
public static @NonNull AbstractMiFirmwareInfo determineFirmwareInfoFor(byte[] wholeFirmwareBytes) {
|
||||||
|
AbstractMiFirmwareInfo[] candidates = getFirmwareInfoCandidatesFor(wholeFirmwareBytes);
|
||||||
|
if (candidates.length == 0) {
|
||||||
|
throw new IllegalArgumentException("Unsupported data (maybe not even a firmware?).");
|
||||||
|
}
|
||||||
|
if (candidates.length == 1) {
|
||||||
|
return candidates[0];
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("don't know for which device the firmware is, matches multiple devices");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AbstractMiFirmwareInfo[] getFirmwareInfoCandidatesFor(byte[] wholeFirmwareBytes) {
|
||||||
|
AbstractMiFirmwareInfo[] candidates = new AbstractMiFirmwareInfo[3];
|
||||||
|
int i = 0;
|
||||||
|
Mi1FirmwareInfo mi1Info = Mi1FirmwareInfo.getInstance(wholeFirmwareBytes);
|
||||||
|
if (mi1Info != null) {
|
||||||
|
candidates[i++] = mi1Info;
|
||||||
|
}
|
||||||
|
Mi1AFirmwareInfo mi1aInfo = Mi1AFirmwareInfo.getInstance(wholeFirmwareBytes);
|
||||||
|
if (mi1aInfo != null) {
|
||||||
|
candidates[i++] = mi1aInfo;
|
||||||
|
}
|
||||||
|
Mi1SFirmwareInfo mi1sInfo = Mi1SFirmwareInfo.getInstance(wholeFirmwareBytes);
|
||||||
|
if (mi1sInfo != null) {
|
||||||
|
candidates[i++] = mi1sInfo;
|
||||||
|
}
|
||||||
|
return Arrays.copyOfRange(candidates, 0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected byte[] wholeFirmwareBytes;
|
||||||
|
|
||||||
|
public AbstractMiFirmwareInfo(@NonNull byte[] wholeFirmwareBytes) {
|
||||||
|
this.wholeFirmwareBytes = wholeFirmwareBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int getFirmwareOffset();
|
||||||
|
|
||||||
|
public abstract int getFirmwareLength();
|
||||||
|
|
||||||
|
public abstract int getFirmwareVersion();
|
||||||
|
|
||||||
|
protected abstract boolean isGenerallySupportedFirmware();
|
||||||
|
|
||||||
|
public abstract boolean isGenerallyCompatibleWith(GBDevice device);
|
||||||
|
|
||||||
|
public @NonNull byte[] getFirmwareBytes() {
|
||||||
|
return Arrays.copyOfRange(wholeFirmwareBytes, getFirmwareOffset(), getFirmwareLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFirmwareVersionMajor() {
|
||||||
|
int version = getFirmwareVersion();
|
||||||
|
if (version > 0) {
|
||||||
|
return (version >> 24);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("bad firmware version: " + version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSingleMiBandFirmware() {
|
||||||
|
// TODO: not sure if this is a correct check!
|
||||||
|
if ((wholeFirmwareBytes[7] & 255) != 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractMiFirmwareInfo getFirst() {
|
||||||
|
if (isSingleMiBandFirmware()) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new UnsupportedOperationException(getClass().getName() + " must override getFirst() and getSecond()");
|
||||||
|
}
|
||||||
|
public AbstractMiFirmwareInfo getSecond() {
|
||||||
|
if (isSingleMiBandFirmware()) {
|
||||||
|
throw new UnsupportedOperationException(getClass().getName() + " only supports on firmware");
|
||||||
|
}
|
||||||
|
throw new UnsupportedOperationException(getClass().getName() + " must override getFirst() and getSecond()");
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandFWHelper;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||||
|
|
||||||
public class DeviceInfo extends AbstractInfo {
|
public class DeviceInfo extends AbstractInfo {
|
||||||
@ -76,7 +75,7 @@ public class DeviceInfo extends AbstractInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean supportsHeartrate() {
|
public boolean supportsHeartrate() {
|
||||||
return isMilli1S();
|
return isMili1S();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -100,7 +99,7 @@ public class DeviceInfo extends AbstractInfo {
|
|||||||
return feature == 5 && appearance == 0 || feature == 0 && hwVersion == 208;
|
return feature == 5 && appearance == 0 || feature == 0 && hwVersion == 208;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMilli1S() {
|
public boolean isMili1S() {
|
||||||
// TODO: this is probably not quite correct, but hopefully sufficient for early 1S support
|
// TODO: this is probably not quite correct, but hopefully sufficient for early 1S support
|
||||||
return feature == 4 && appearance == 0 || feature == 4 && hwVersion == 4;
|
return feature == 4 && appearance == 0 || feature == 4 && hwVersion == 4;
|
||||||
}
|
}
|
||||||
@ -112,7 +111,7 @@ public class DeviceInfo extends AbstractInfo {
|
|||||||
if (isMili1A()) {
|
if (isMili1A()) {
|
||||||
return MiBandConst.MI_1A;
|
return MiBandConst.MI_1A;
|
||||||
}
|
}
|
||||||
if (isMilli1S()) {
|
if (isMili1S()) {
|
||||||
return MiBandConst.MI_1S;
|
return MiBandConst.MI_1S;
|
||||||
}
|
}
|
||||||
return "?";
|
return "?";
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
|
||||||
|
public class Mi1AFirmwareInfo extends AbstractMi1FirmwareInfo {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(Mi1AFirmwareInfo.class);
|
||||||
|
|
||||||
|
public static Mi1AFirmwareInfo getInstance(byte[] wholeFirmwareBytes) {
|
||||||
|
Mi1AFirmwareInfo info = new Mi1AFirmwareInfo(wholeFirmwareBytes);
|
||||||
|
if (info.isGenerallySupportedFirmware()) {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
LOG.info("firmware not supported");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Mi1AFirmwareInfo(@NonNull byte[] wholeFirmwareBytes) {
|
||||||
|
super(wholeFirmwareBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getSupportedMajorVersion() {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGenerallyCompatibleWith(GBDevice device) {
|
||||||
|
String hwVersion = device.getHardwareVersion();
|
||||||
|
return MiBandConst.MI_1A.equals(hwVersion);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
|
||||||
|
public class Mi1FirmwareInfo extends AbstractMi1FirmwareInfo {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(Mi1FirmwareInfo.class);
|
||||||
|
|
||||||
|
public static Mi1FirmwareInfo getInstance(byte[] wholeFirmwareBytes) {
|
||||||
|
Mi1FirmwareInfo info = new Mi1FirmwareInfo(wholeFirmwareBytes);
|
||||||
|
if (info.isGenerallySupportedFirmware()) {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
LOG.info("firmware not supported");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Mi1FirmwareInfo(@NonNull byte[] wholeFirmwareBytes) {
|
||||||
|
super(wholeFirmwareBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getSupportedMajorVersion() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGenerallyCompatibleWith(GBDevice device) {
|
||||||
|
String hwVersion = device.getHardwareVersion();
|
||||||
|
return MiBandConst.MI_1.equals(hwVersion);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FW1 is Mi Band firmware
|
||||||
|
* FW2 is heartrate firmware
|
||||||
|
*/
|
||||||
|
public class Mi1SFirmwareInfo extends AbstractMi1SFirmwareInfo {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(AbstractMi1FirmwareInfo.class);
|
||||||
|
|
||||||
|
private final Mi1SFirmwareInfoFW1 fw1Info;
|
||||||
|
private final Mi1SFirmwareInfoFW2 fw2Info;
|
||||||
|
|
||||||
|
private Mi1SFirmwareInfo(byte[] wholeFirmwareBytes) {
|
||||||
|
super(wholeFirmwareBytes);
|
||||||
|
fw1Info = new Mi1SFirmwareInfoFW1(wholeFirmwareBytes);
|
||||||
|
fw2Info = new Mi1SFirmwareInfoFW2(wholeFirmwareBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractMiFirmwareInfo getFirst() {
|
||||||
|
return fw1Info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractMiFirmwareInfo getSecond() {
|
||||||
|
return fw2Info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable Mi1SFirmwareInfo getInstance(byte[] wholeFirmwareBytes) {
|
||||||
|
Mi1SFirmwareInfo info = new Mi1SFirmwareInfo(wholeFirmwareBytes);
|
||||||
|
if (info.isGenerallySupportedFirmware()) {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
LOG.info("firmware not supported");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isGenerallySupportedFirmware() {
|
||||||
|
if (isSingleMiBandFirmware()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return fw1Info.isGenerallySupportedFirmware() && fw2Info.isGenerallySupportedFirmware();
|
||||||
|
} catch (IndexOutOfBoundsException ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirmwareOffset() {
|
||||||
|
throw new UnsupportedOperationException("call this method on getFirmwareXInfo()");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirmwareLength() {
|
||||||
|
throw new UnsupportedOperationException("call this method on getFirmwareXInfo()");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirmwareVersion() {
|
||||||
|
throw new UnsupportedOperationException("call this method on getFirmwareXInfo()");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FW1 is Mi Band firmware
|
||||||
|
* FW2 is heartrate firmware
|
||||||
|
*/
|
||||||
|
public class Mi1SFirmwareInfoFW1 extends AbstractMi1SFirmwareInfo {
|
||||||
|
|
||||||
|
private static final int MI1S_FW_BASE_OFFSET = 1092;
|
||||||
|
|
||||||
|
Mi1SFirmwareInfoFW1(@NonNull byte[] wholeFirmwareBytes) {
|
||||||
|
super(wholeFirmwareBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirmwareOffset()
|
||||||
|
{
|
||||||
|
return (wholeFirmwareBytes[12] & 255) << 24
|
||||||
|
| (wholeFirmwareBytes[13] & 255) << 16
|
||||||
|
| (wholeFirmwareBytes[14] & 255) << 8
|
||||||
|
| (wholeFirmwareBytes[15] & 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirmwareLength()
|
||||||
|
{
|
||||||
|
return (wholeFirmwareBytes[16] & 255) << 24
|
||||||
|
| (wholeFirmwareBytes[17] & 255) << 16
|
||||||
|
| (wholeFirmwareBytes[18] & 255) << 8
|
||||||
|
| (wholeFirmwareBytes[19] & 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirmwareVersion()
|
||||||
|
{
|
||||||
|
return (wholeFirmwareBytes[8] & 255) << 24
|
||||||
|
| (wholeFirmwareBytes[9] & 255) << 16
|
||||||
|
| (wholeFirmwareBytes[10] & 255) << 8
|
||||||
|
| wholeFirmwareBytes[11] & 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isGenerallySupportedFirmware() {
|
||||||
|
try {
|
||||||
|
int majorVersion = getFirmwareVersionMajor();
|
||||||
|
return majorVersion == 4;
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FW1 is Mi Band firmware
|
||||||
|
* FW2 is heartrate firmware
|
||||||
|
*/
|
||||||
|
public class Mi1SFirmwareInfoFW2 extends AbstractMi1SFirmwareInfo {
|
||||||
|
|
||||||
|
Mi1SFirmwareInfoFW2(@NonNull byte[] wholeFirmwareBytes) {
|
||||||
|
super(wholeFirmwareBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirmwareOffset()
|
||||||
|
{
|
||||||
|
return (wholeFirmwareBytes[26] & 255) << 24
|
||||||
|
| (wholeFirmwareBytes[27] & 255) << 16
|
||||||
|
| (wholeFirmwareBytes[28] & 255) << 8
|
||||||
|
| (wholeFirmwareBytes[29] & 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirmwareLength()
|
||||||
|
{
|
||||||
|
return (wholeFirmwareBytes[30] & 255) << 24
|
||||||
|
| (wholeFirmwareBytes[31] & 255) << 16
|
||||||
|
| (wholeFirmwareBytes[32] & 255) << 8
|
||||||
|
| (wholeFirmwareBytes[33] & 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isGenerallySupportedFirmware() {
|
||||||
|
try {
|
||||||
|
int majorVersion = getFirmwareVersionMajor();
|
||||||
|
return majorVersion == 1;
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFirmwareVersion()
|
||||||
|
{
|
||||||
|
return (wholeFirmwareBytes[22] & 255) << 24
|
||||||
|
| (wholeFirmwareBytes[23] & 255) << 16
|
||||||
|
| (wholeFirmwareBytes[24] & 255) << 8
|
||||||
|
| wholeFirmwareBytes[25] & 255;
|
||||||
|
}
|
||||||
|
}
|
@ -1,68 +0,0 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FW1 is Mi Band firmware
|
|
||||||
* FW2 is heartrate firmware
|
|
||||||
*/
|
|
||||||
public class Mi1SInfo {
|
|
||||||
|
|
||||||
public static int getFirmware2OffsetIn(@NonNull byte[] wholeFirmwareBytes)
|
|
||||||
{
|
|
||||||
return (wholeFirmwareBytes[26] & 255) << 24
|
|
||||||
| (wholeFirmwareBytes[27] & 255) << 16
|
|
||||||
| (wholeFirmwareBytes[28] & 255) << 8
|
|
||||||
| (wholeFirmwareBytes[29] & 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getFirmware2LengthIn(@NonNull byte[] wholeFirmwareBytes)
|
|
||||||
{
|
|
||||||
return (wholeFirmwareBytes[30] & 255) << 24
|
|
||||||
| (wholeFirmwareBytes[31] & 255) << 16
|
|
||||||
| (wholeFirmwareBytes[32] & 255) << 8
|
|
||||||
| (wholeFirmwareBytes[33] & 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getFirmware1OffsetIn(@NonNull byte[] wholeFirmwareBytes)
|
|
||||||
{
|
|
||||||
return (wholeFirmwareBytes[12] & 255) << 24
|
|
||||||
| (wholeFirmwareBytes[13] & 255) << 16
|
|
||||||
| (wholeFirmwareBytes[14] & 255) << 8
|
|
||||||
| (wholeFirmwareBytes[15] & 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getFirmware1LengthIn(@NonNull byte[] wholeFirmwareBytes)
|
|
||||||
{
|
|
||||||
return (wholeFirmwareBytes[16] & 255) << 24
|
|
||||||
| (wholeFirmwareBytes[17] & 255) << 16
|
|
||||||
| (wholeFirmwareBytes[18] & 255) << 8
|
|
||||||
| (wholeFirmwareBytes[19] & 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getFirmware1VersionFrom(@NonNull byte[] wholeFirmwareBytes)
|
|
||||||
{
|
|
||||||
return (wholeFirmwareBytes[8] & 255) << 24
|
|
||||||
| (wholeFirmwareBytes[9] & 255) << 16
|
|
||||||
| (wholeFirmwareBytes[10] & 255) << 8
|
|
||||||
| wholeFirmwareBytes[11] & 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getFirmware2VersionFrom(@NonNull byte[] wholeFirmwareBytes)
|
|
||||||
{
|
|
||||||
return (wholeFirmwareBytes[22] & 255) << 24
|
|
||||||
| (wholeFirmwareBytes[23] & 255) << 16
|
|
||||||
| (wholeFirmwareBytes[24] & 255) << 8
|
|
||||||
| wholeFirmwareBytes[25] & 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: this method is wrong. We don't know a way to check if a firmware file
|
|
||||||
// contains one or more firmwares.
|
|
||||||
public static boolean isSingleMiBandFirmware(@NonNull byte[] wholeFirmwareBytes) {
|
|
||||||
if ((wholeFirmwareBytes[7] & 255) != 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -18,7 +18,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.Mi1SInfo;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.AbstractMiFirmwareInfo;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
@ -28,8 +28,6 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
|
|
||||||
private final Uri uri;
|
private final Uri uri;
|
||||||
private boolean firmwareInfoSent = false;
|
private boolean firmwareInfoSent = false;
|
||||||
// private byte[] newFirmware;
|
|
||||||
// private boolean rebootWhenBandReady = false;
|
|
||||||
private UpdateCoordinator updateCoordinator;
|
private UpdateCoordinator updateCoordinator;
|
||||||
|
|
||||||
public UpdateFirmwareOperation(Uri uri, MiBandSupport support) {
|
public UpdateFirmwareOperation(Uri uri, MiBandSupport support) {
|
||||||
@ -41,11 +39,16 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
protected void doPerform() throws IOException {
|
protected void doPerform() throws IOException {
|
||||||
MiBandFWHelper mFwHelper = new MiBandFWHelper(uri, getContext());
|
MiBandFWHelper mFwHelper = new MiBandFWHelper(uri, getContext());
|
||||||
|
|
||||||
// if (getSupport().supportsHeartRate()) {
|
AbstractMiFirmwareInfo firmwareInfo = mFwHelper.getFirmwareInfo();
|
||||||
updateCoordinator = prepareFirmwareInfo1S(mFwHelper.getFw());
|
if (!firmwareInfo.isGenerallyCompatibleWith(getDevice())) {
|
||||||
// } else {
|
throw new IOException("Firmware is not compatible with the given device: " + getDevice().getAddress());
|
||||||
// updateCoordinator = sendFirmwareInfo(mFwHelper.getFw(), mFwHelper.getFirmwareVersion());
|
}
|
||||||
// }
|
|
||||||
|
if (getSupport().supportsHeartRate()) {
|
||||||
|
updateCoordinator = prepareFirmwareInfo1S(firmwareInfo);
|
||||||
|
} else {
|
||||||
|
updateCoordinator = prepareFirmwareInfo(mFwHelper.getFw(), mFwHelper.getFirmwareVersion());
|
||||||
|
}
|
||||||
|
|
||||||
updateCoordinator.initNextOperation();
|
updateCoordinator.initNextOperation();
|
||||||
// updateCoordinator.initNextOperation(); // FIXME: remove, just testing mi band 1s fw update
|
// updateCoordinator.initNextOperation(); // FIXME: remove, just testing mi band 1s fw update
|
||||||
@ -75,7 +78,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* React to unsolicited messages sent by the Mi Band to the MiBandService.UUID_CHARACTERISTIC_NOTIFICATION
|
* React to messages sent by the Mi Band to the MiBandService.UUID_CHARACTERISTIC_NOTIFICATION
|
||||||
* characteristic,
|
* characteristic,
|
||||||
* These messages appear to be always 1 byte long, with values that are listed in MiBandService.
|
* These messages appear to be always 1 byte long, with values that are listed in MiBandService.
|
||||||
* It is not excluded that there are further values which are still unknown.
|
* It is not excluded that there are further values which are still unknown.
|
||||||
@ -97,25 +100,19 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
|
|
||||||
switch (value[0]) {
|
switch (value[0]) {
|
||||||
case MiBandService.NOTIFY_FW_CHECK_SUCCESS:
|
case MiBandService.NOTIFY_FW_CHECK_SUCCESS:
|
||||||
// if (firmwareInfoSent && newFirmware != null) {
|
|
||||||
if (firmwareInfoSent) {
|
if (firmwareInfoSent) {
|
||||||
GB.toast(getContext(), "Firmware metadata successfully sent.", Toast.LENGTH_LONG, GB.INFO);
|
GB.toast(getContext(), "Firmware metadata successfully sent.", Toast.LENGTH_LONG, GB.INFO);
|
||||||
if (updateCoordinator.sendFwData()) {
|
if (!updateCoordinator.sendFwData()) {
|
||||||
// if (sendFirmwareData(newFirmware)) {
|
|
||||||
// rebootWhenBandReady = true; // disabled for testing
|
|
||||||
} else {
|
|
||||||
//TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do?
|
//TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do?
|
||||||
GB.toast(getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR);
|
GB.toast(getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR);
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
firmwareInfoSent = false;
|
firmwareInfoSent = false;
|
||||||
// newFirmware = null;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MiBandService.NOTIFY_FW_CHECK_FAILED:
|
case MiBandService.NOTIFY_FW_CHECK_FAILED:
|
||||||
GB.toast(getContext().getString(R.string.updatefirmwareoperation_metadata_updateproblem), Toast.LENGTH_LONG, GB.ERROR);
|
GB.toast(getContext().getString(R.string.updatefirmwareoperation_metadata_updateproblem), Toast.LENGTH_LONG, GB.ERROR);
|
||||||
firmwareInfoSent = false;
|
firmwareInfoSent = false;
|
||||||
// newFirmware = null;
|
|
||||||
done();
|
done();
|
||||||
break;
|
break;
|
||||||
case MiBandService.NOTIFY_FIRMWARE_UPDATE_SUCCESS:
|
case MiBandService.NOTIFY_FIRMWARE_UPDATE_SUCCESS:
|
||||||
@ -130,7 +127,6 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
GB.toast(getContext(), getContext().getString(R.string.updatefirmwareoperation_update_complete_rebooting), Toast.LENGTH_LONG, GB.INFO);
|
GB.toast(getContext(), getContext().getString(R.string.updatefirmwareoperation_update_complete_rebooting), Toast.LENGTH_LONG, GB.INFO);
|
||||||
GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_update_complete), false, 100, getContext());
|
GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_update_complete), false, 100, getContext());
|
||||||
getSupport().onReboot();
|
getSupport().onReboot();
|
||||||
// rebootWhenBandReady = false;
|
|
||||||
} else {
|
} else {
|
||||||
LOG.error("BUG: Successful firmware update without reboot???");
|
LOG.error("BUG: Successful firmware update without reboot???");
|
||||||
}
|
}
|
||||||
@ -140,7 +136,6 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
//TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do?
|
//TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do?
|
||||||
GB.toast(getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR);
|
GB.toast(getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR);
|
||||||
GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_write_failed), false, 0, getContext());
|
GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_write_failed), false, 0, getContext());
|
||||||
// rebootWhenBandReady = false;
|
|
||||||
done();
|
done();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -150,63 +145,41 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * Prepare the MiBand to receive the new firmware data.
|
* Prepare the MiBand to receive the new firmware data.
|
||||||
// * Some information about the new firmware version have to be pushed to the MiBand before sending
|
* Some information about the new firmware version have to be pushed to the MiBand before sending
|
||||||
// * the actual firmare.
|
* the actual firmare.
|
||||||
// * <p/>
|
* <p/>
|
||||||
// * The Mi Band will send a notification after receiving these data to confirm if the metadata looks good to it.
|
* The Mi Band will send a notification after receiving these data to confirm if the metadata looks good to it.
|
||||||
// *
|
*
|
||||||
// * @param fwBytes
|
* @param newFwVersion
|
||||||
// * @param newFwVersion
|
* @see MiBandSupport#handleNotificationNotif
|
||||||
// * @see MiBandSupport#handleNotificationNotif
|
*/
|
||||||
// */
|
private UpdateCoordinator prepareFirmwareInfo(byte[] fwBytes, int newFwVersion) throws IOException {
|
||||||
// private byte[] sendFirmwareInfo(int currentFwVersion, int newFwVersion, int newFwSize, int checksum) throws IOException {
|
int newFwSize = fwBytes.length;
|
||||||
// private UpdateCoordinator sendFirmwareInfo(byte[] fwBytes, int newFwVersion) throws IOException {
|
String mMac = getDevice().getAddress();
|
||||||
// int newFwSize = fwBytes.length;
|
String[] mMacOctets = mMac.split(":");
|
||||||
// String mMac = getDevice().getAddress();
|
int currentFwVersion = getSupport().getDeviceInfo().getFirmwareVersion();
|
||||||
// String[] mMacOctets = mMac.split(":");
|
int checksum = (Integer.decode("0x" + mMacOctets[4]) << 8 | Integer.decode("0x" + mMacOctets[5])) ^ CheckSums.getCRC16(fwBytes);
|
||||||
// int currentFwVersion = getSupport().getDeviceInfo().getFirmwareVersion();
|
|
||||||
// int checksum = (Integer.decode("0x" + mMacOctets[4]) << 8 | Integer.decode("0x" + mMacOctets[5])) ^ CheckSums.getCRC16(fwBytes);
|
|
||||||
//
|
|
||||||
// byte[] fwInfo = new byte[]{
|
|
||||||
// MiBandService.COMMAND_SEND_FIRMWARE_INFO,
|
|
||||||
// (byte) currentFwVersion,
|
|
||||||
// (byte) (currentFwVersion >> 8),
|
|
||||||
// (byte) (currentFwVersion >> 16),
|
|
||||||
// (byte) (currentFwVersion >> 24),
|
|
||||||
// (byte) newFwVersion,
|
|
||||||
// (byte) (newFwVersion >> 8),
|
|
||||||
// (byte) (newFwVersion >> 16),
|
|
||||||
// (byte) (newFwVersion >> 24),
|
|
||||||
// (byte) newFwSize,
|
|
||||||
// (byte) (newFwSize >> 8),
|
|
||||||
// (byte) checksum,
|
|
||||||
// (byte) (checksum >> 8)
|
|
||||||
//// (byte) (checksum >> 8),
|
|
||||||
//// (byte) 0 // TEST, only for Mi1S!
|
|
||||||
// };
|
|
||||||
// return new SingleUpdateCoordinator(fwInfo, fwBytes);
|
|
||||||
// }
|
|
||||||
|
|
||||||
private UpdateCoordinator prepareFirmwareInfo1S(byte[] wholeFirmwareBytes) {
|
byte[] fwInfo = prepareFirmwareUpdateA(currentFwVersion, newFwVersion, newFwSize, checksum);
|
||||||
int fw2Version = Mi1SInfo.getFirmware2VersionFrom(wholeFirmwareBytes);
|
return new SingleUpdateCoordinator(fwInfo, fwBytes, true);
|
||||||
int fw2Offset = Mi1SInfo.getFirmware2OffsetIn(wholeFirmwareBytes);
|
}
|
||||||
int fw2Length = Mi1SInfo.getFirmware2LengthIn(wholeFirmwareBytes);
|
|
||||||
|
|
||||||
int fw1Version = Mi1SInfo.getFirmware1VersionFrom(wholeFirmwareBytes);
|
private UpdateCoordinator prepareFirmwareInfo1S(AbstractMiFirmwareInfo info) {
|
||||||
int fw1Offset = Mi1SInfo.getFirmware1OffsetIn(wholeFirmwareBytes);
|
if (info.isSingleMiBandFirmware()) {
|
||||||
int fw1Length = Mi1SInfo.getFirmware1LengthIn(wholeFirmwareBytes);
|
throw new IllegalArgumentException("preparing single fw not allowed for 1S");
|
||||||
|
}
|
||||||
|
int fw2Version = info.getSecond().getFirmwareVersion();
|
||||||
|
int fw1Version = info.getFirst().getFirmwareVersion();
|
||||||
|
|
||||||
String[] mMacOctets = getDevice().getAddress().split(":");
|
String[] mMacOctets = getDevice().getAddress().split(":");
|
||||||
int encodedMac = (Integer.decode("0x" + mMacOctets[4]) << 8 | Integer.decode("0x" + mMacOctets[5]));
|
int encodedMac = (Integer.decode("0x" + mMacOctets[4]) << 8 | Integer.decode("0x" + mMacOctets[5]));
|
||||||
|
|
||||||
byte[] fw2Bytes = new byte[fw2Length];
|
byte[] fw2Bytes = info.getSecond().getFirmwareBytes();
|
||||||
System.arraycopy(wholeFirmwareBytes, fw2Offset, fw2Bytes, 0, fw2Length);
|
|
||||||
int fw2Checksum = CheckSums.getCRC16(fw2Bytes) ^ encodedMac;
|
int fw2Checksum = CheckSums.getCRC16(fw2Bytes) ^ encodedMac;
|
||||||
|
|
||||||
byte[] fw1Bytes = new byte[fw1Length];
|
byte[] fw1Bytes = info.getFirst().getFirmwareBytes();
|
||||||
System.arraycopy(wholeFirmwareBytes, fw1Offset, fw1Bytes, 0, fw1Length);
|
|
||||||
int fw1Checksum = encodedMac ^ CheckSums.getCRC16(fw1Bytes);
|
int fw1Checksum = encodedMac ^ CheckSums.getCRC16(fw1Bytes);
|
||||||
|
|
||||||
// check firmware validity?
|
// check firmware validity?
|
||||||
@ -215,22 +188,18 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
int fw2OldVersion = getSupport().getDeviceInfo().getHeartrateFirmwareVersion();
|
int fw2OldVersion = getSupport().getDeviceInfo().getHeartrateFirmwareVersion();
|
||||||
|
|
||||||
boolean rebootWhenFinished = true;
|
boolean rebootWhenFinished = true;
|
||||||
if (Mi1SInfo.isSingleMiBandFirmware(wholeFirmwareBytes)) {
|
if (info.isSingleMiBandFirmware()) {
|
||||||
LOG.info("is single Mi Band firmware");
|
LOG.info("is single Mi Band firmware");
|
||||||
byte[] fw1Info = prepareFirmwareInfo(fw1Bytes, fw1OldVersion, fw1Version, fw1Checksum, 0, rebootWhenFinished /*, progress monitor */);
|
byte[] fw1Info = prepareFirmwareInfo(fw1Bytes, fw1OldVersion, fw1Version, fw1Checksum, 0, rebootWhenFinished /*, progress monitor */);
|
||||||
return new SingleUpdateCoordinator(fw1Info, fw1Bytes, rebootWhenFinished);
|
return new SingleUpdateCoordinator(fw1Info, fw1Bytes, rebootWhenFinished);
|
||||||
} else {
|
} else {
|
||||||
LOG.info("is multi Mi Band firmware, sending fw2 (hr) now");
|
LOG.info("is multi Mi Band firmware, sending fw2 (hr) first");
|
||||||
byte[] fw2Info = prepareFirmwareInfo(fw2Bytes, fw2OldVersion, fw2Version, fw2Checksum, 1, rebootWhenFinished /*, progress monitor */);
|
byte[] fw2Info = prepareFirmwareInfo(fw2Bytes, fw2OldVersion, fw2Version, fw2Checksum, 1, rebootWhenFinished /*, progress monitor */);
|
||||||
byte[] fw1Info = prepareFirmwareInfo(fw1Bytes, fw1OldVersion, fw1Version, fw1Checksum, 1, rebootWhenFinished /*, progress monitor */);
|
byte[] fw1Info = prepareFirmwareInfo(fw1Bytes, fw1OldVersion, fw1Version, fw1Checksum, 1, rebootWhenFinished /*, progress monitor */);
|
||||||
return new DoubleUpdateCoordinator(fw1Info, fw1Bytes, fw2Info, fw2Bytes, rebootWhenFinished);
|
return new DoubleUpdateCoordinator(fw1Info, fw1Bytes, fw2Info, fw2Bytes, rebootWhenFinished);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private Transaction createUpdateFirmwareTransaction() {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
private byte[] prepareFirmwareInfo(byte[] fwBytes, int currentFwVersion, int newFwVersion, int checksum, int something, boolean reboot) {
|
private byte[] prepareFirmwareInfo(byte[] fwBytes, int currentFwVersion, int newFwVersion, int checksum, int something, boolean reboot) {
|
||||||
byte[] fwInfo;
|
byte[] fwInfo;
|
||||||
switch (something) {
|
switch (something) {
|
||||||
@ -262,12 +231,6 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
(byte) checksum,
|
(byte) checksum,
|
||||||
(byte) (checksum >> 8)
|
(byte) (checksum >> 8)
|
||||||
};
|
};
|
||||||
// byte[] fwInfo = new byte[]{
|
|
||||||
// MiBandService.COMMAND_SEND_FIRMWARE_INFO
|
|
||||||
// (byte) currentFwVersion, (byte) (currentFwVersion >> 8), (byte) (currentFwVersion >> 16), (byte) (currentFwVersion >> 24),
|
|
||||||
// (byte) newFwVersion, (byte) (newFwVersion >> 8), (byte) (newFwVersion >> 16), (byte) (newFwVersion >> 24),
|
|
||||||
// (byte) newFwSize, (byte) (newFwSize >> 8),
|
|
||||||
// (byte) checksum, (byte) (checksum >> 8)})) {
|
|
||||||
return fwInfo;
|
return fwInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,21 +249,8 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
(byte) (newFwSize >> 8),
|
(byte) (newFwSize >> 8),
|
||||||
(byte) checksum,
|
(byte) checksum,
|
||||||
(byte) (checksum >> 8),
|
(byte) (checksum >> 8),
|
||||||
(byte) something // 0 TEST, only for Mi1S!
|
(byte) something
|
||||||
};
|
};
|
||||||
|
|
||||||
// // send to CONTROL POINT:
|
|
||||||
// if (!this.b(CONTROL_POINT, new byte[]{7,
|
|
||||||
// (byte) currentFwVersion, (byte) (currentFwVersion >> 8), (byte) (currentFwVersion >> 16), (byte) (currentFwVersion >> 24),
|
|
||||||
// (byte) newFwVersion, (byte) (newFwVersion >> 8), (byte) (newFwVersion >> 16), (byte) (newFwVersion >> 24),
|
|
||||||
// (byte) newFwSize, (byte) (newFwSize >> 8),
|
|
||||||
// (byte) checksum, (byte) (checksum >> 8), (byte) something})) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// // wait for bq != -1
|
|
||||||
// if (bq == 12) {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
return fwInfo;
|
return fwInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,6 +338,9 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean sendFwData() {
|
public boolean sendFwData() {
|
||||||
|
// if (true) {
|
||||||
|
// return true; // FIXME: temporarily disabled firmware sending
|
||||||
|
// }
|
||||||
return sendFirmwareData(getFirmwareBytes());
|
return sendFirmwareData(getFirmwareBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import org.junit.Test;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandFWHelper;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandFWHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
@ -18,19 +19,19 @@ public class FirmwareTest {
|
|||||||
private static final int MI1S_FW1_VERSION = 0;
|
private static final int MI1S_FW1_VERSION = 0;
|
||||||
private static final int MI1S_FW2_VERSION = 0;
|
private static final int MI1S_FW2_VERSION = 0;
|
||||||
|
|
||||||
|
private static final int SINGLE = 1;
|
||||||
|
private static final int DOUBLE = 2;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFirmwareMi() throws Exception{
|
public void testFirmwareMi1() throws Exception{
|
||||||
byte[] wholeFw = getFirmwareMi();
|
byte[] wholeFw = getFirmwareMi();
|
||||||
Assert.assertNotNull(wholeFw);
|
Assert.assertNotNull(wholeFw);
|
||||||
|
|
||||||
Assert.assertTrue(Mi1SInfo.isSingleMiBandFirmware(wholeFw));
|
AbstractMiFirmwareInfo info = getFirmwareInfo(wholeFw, SINGLE);
|
||||||
int calculatedLength = Mi1SInfo.getFirmware1LengthIn(wholeFw);
|
int calculatedVersion = info.getFirmwareVersion();
|
||||||
Assert.assertTrue("Unexpected firmware length: " + wholeFw.length, calculatedLength < wholeFw.length);
|
|
||||||
int calculatedVersion = Mi1SInfo.getFirmware1VersionFrom(wholeFw);
|
|
||||||
// Assert.assertEquals("Unexpected firmware version: " + calculatedVersion, MI_FW_VERSION, calculatedVersion);
|
|
||||||
|
|
||||||
String version = MiBandFWHelper.formatFirmwareVersion(calculatedVersion);
|
String version = MiBandFWHelper.formatFirmwareVersion(calculatedVersion);
|
||||||
Assert.assertTrue(version.startsWith("1."));
|
Assert.assertTrue(version.startsWith("1."));
|
||||||
|
// Assert.assertEquals("Unexpected firmware version: " + calculatedVersion, MI_FW_VERSION, calculatedVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -38,14 +39,11 @@ public class FirmwareTest {
|
|||||||
byte[] wholeFw = getFirmwareMi1A();
|
byte[] wholeFw = getFirmwareMi1A();
|
||||||
Assert.assertNotNull(wholeFw);
|
Assert.assertNotNull(wholeFw);
|
||||||
|
|
||||||
Assert.assertTrue(Mi1SInfo.isSingleMiBandFirmware(wholeFw));
|
AbstractMiFirmwareInfo info = getFirmwareInfo(wholeFw, SINGLE);
|
||||||
int calculatedLength = Mi1SInfo.getFirmware1LengthIn(wholeFw);
|
int calculatedVersion = info.getFirmwareVersion();
|
||||||
Assert.assertTrue("Unexpected firmware length: " + wholeFw.length, calculatedLength < wholeFw.length);
|
|
||||||
int calculatedVersion = Mi1SInfo.getFirmware1VersionFrom(wholeFw);
|
|
||||||
// Assert.assertEquals("Unexpected firmware version: " + calculatedVersion, MI1A_FW_VERSION, calculatedVersion);
|
|
||||||
|
|
||||||
String version = MiBandFWHelper.formatFirmwareVersion(calculatedVersion);
|
String version = MiBandFWHelper.formatFirmwareVersion(calculatedVersion);
|
||||||
Assert.assertTrue(version.startsWith("5."));
|
Assert.assertTrue(version.startsWith("5."));
|
||||||
|
// Assert.assertEquals("Unexpected firmware version: " + calculatedVersion, MI1A_FW_VERSION, calculatedVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -53,31 +51,71 @@ public class FirmwareTest {
|
|||||||
byte[] wholeFw = getFirmwareMi1S();
|
byte[] wholeFw = getFirmwareMi1S();
|
||||||
Assert.assertNotNull(wholeFw);
|
Assert.assertNotNull(wholeFw);
|
||||||
|
|
||||||
Assert.assertFalse(Mi1SInfo.isSingleMiBandFirmware(wholeFw));
|
AbstractMiFirmwareInfo info = getFirmwareInfo(wholeFw, DOUBLE);
|
||||||
|
|
||||||
// Mi Band version
|
// Mi Band version
|
||||||
int calculatedLengthFw1 = Mi1SInfo.getFirmware1LengthIn(wholeFw);
|
int calculatedLengthFw1 = info.getFirst().getFirmwareLength();
|
||||||
int calculatedOffsetFw1 = Mi1SInfo.getFirmware1OffsetIn(wholeFw);
|
int calculatedOffsetFw1 = info.getFirst().getFirmwareOffset();
|
||||||
int endIndexFw1 = calculatedOffsetFw1 + calculatedLengthFw1;
|
int endIndexFw1 = calculatedOffsetFw1 + calculatedLengthFw1;
|
||||||
|
|
||||||
int calculatedLengthFw2 = Mi1SInfo.getFirmware2LengthIn(wholeFw);
|
int calculatedLengthFw2 = info.getSecond().getFirmwareLength();
|
||||||
int calculatedOffsetFw2 = Mi1SInfo.getFirmware2OffsetIn(wholeFw);
|
int calculatedOffsetFw2 = info.getSecond().getFirmwareOffset();
|
||||||
int endIndexFw2 = calculatedOffsetFw2 + calculatedLengthFw2;
|
int endIndexFw2 = calculatedOffsetFw2 + calculatedLengthFw2;
|
||||||
|
|
||||||
Assert.assertTrue(endIndexFw1 <= wholeFw.length - calculatedLengthFw2);
|
Assert.assertTrue(endIndexFw1 <= wholeFw.length - calculatedLengthFw2);
|
||||||
Assert.assertTrue(endIndexFw2 <= wholeFw.length);
|
Assert.assertTrue(endIndexFw2 <= wholeFw.length);
|
||||||
|
|
||||||
Assert.assertTrue(endIndexFw1 <= calculatedOffsetFw2);
|
Assert.assertTrue(endIndexFw1 <= calculatedOffsetFw2);
|
||||||
int calculatedVersionFw1 = Mi1SInfo.getFirmware1VersionFrom(wholeFw);
|
int calculatedVersionFw1 = info.getFirst().getFirmwareVersion();
|
||||||
// Assert.assertEquals("Unexpected firmware 1 version: " + calculatedVersionFw1, MI1S_FW1_VERSION, calculatedVersionFw1);
|
// Assert.assertEquals("Unexpected firmware 1 version: " + calculatedVersionFw1, MI1S_FW1_VERSION, calculatedVersionFw1);
|
||||||
String version1 = MiBandFWHelper.formatFirmwareVersion(calculatedVersionFw1);
|
String version1 = MiBandFWHelper.formatFirmwareVersion(calculatedVersionFw1);
|
||||||
Assert.assertTrue(version1.startsWith("4."));
|
Assert.assertTrue(version1.startsWith("4."));
|
||||||
|
|
||||||
// HR version
|
// HR version
|
||||||
int calculatedVersionFw2 = Mi1SInfo.getFirmware2VersionFrom(wholeFw);
|
int calculatedVersionFw2 = info.getSecond().getFirmwareVersion();
|
||||||
// Assert.assertEquals("Unexpected firmware 2 version: " + calculatedVersionFw2, MI1S_FW2_VERSION, calculatedVersionFw2);
|
// Assert.assertEquals("Unexpected firmware 2 version: " + calculatedVersionFw2, MI1S_FW2_VERSION, calculatedVersionFw2);
|
||||||
String version2 = MiBandFWHelper.formatFirmwareVersion(calculatedVersionFw2);
|
String version2 = MiBandFWHelper.formatFirmwareVersion(calculatedVersionFw2);
|
||||||
Assert.assertTrue(version2.startsWith("1."));
|
Assert.assertTrue(version2.startsWith("1."));
|
||||||
|
|
||||||
|
try {
|
||||||
|
info.getFirmwareVersion();
|
||||||
|
Assert.fail("should not get fw version from AbstractMi1SFirmwareInfo");
|
||||||
|
} catch (UnsupportedOperationException expected) {}
|
||||||
|
|
||||||
|
Assert.assertNotEquals(info.getFirst().getFirmwareOffset(), info.getSecond().getFirmwareOffset());
|
||||||
|
Assert.assertFalse(Arrays.equals(info.getFirst().getFirmwareBytes(), info.getSecond().getFirmwareBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbstractMiFirmwareInfo getFirmwareInfo(byte[] wholeFw, int numFirmwares) {
|
||||||
|
AbstractMiFirmwareInfo info = AbstractMiFirmwareInfo.determineFirmwareInfoFor(wholeFw);
|
||||||
|
switch (numFirmwares) {
|
||||||
|
case SINGLE: {
|
||||||
|
Assert.assertTrue("should be single miband firmware", info.isSingleMiBandFirmware());
|
||||||
|
Assert.assertSame(info, info.getFirst());
|
||||||
|
try {
|
||||||
|
info.getSecond();
|
||||||
|
Assert.fail("should throw UnsuportedOperationException");
|
||||||
|
} catch (UnsupportedOperationException expected) {}
|
||||||
|
int calculatedLength = info.getFirmwareLength();
|
||||||
|
Assert.assertTrue("Unexpected firmware length: " + wholeFw.length, calculatedLength <= wholeFw.length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DOUBLE: {
|
||||||
|
Assert.assertFalse("should not be single miband firmware", info.isSingleMiBandFirmware());
|
||||||
|
Assert.assertNotSame(info, info.getFirst());
|
||||||
|
Assert.assertNotSame(info, info.getSecond());
|
||||||
|
Assert.assertNotSame(info.getFirst(), info.getSecond());
|
||||||
|
int calculatedLength = info.getFirst().getFirmwareLength();
|
||||||
|
Assert.assertTrue("Unexpected firmware length: " + wholeFw.length, calculatedLength <= wholeFw.length);
|
||||||
|
calculatedLength = info.getSecond().getFirmwareLength();
|
||||||
|
Assert.assertTrue("Unexpected firmware length: " + wholeFw.length, calculatedLength <= wholeFw.length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Assert.fail("unexpected numFirmwares: " + numFirmwares);
|
||||||
|
}
|
||||||
|
Assert.assertTrue(info.isGenerallySupportedFirmware());
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private File getFirmwareDir() {
|
private File getFirmwareDir() {
|
||||||
|
Loading…
Reference in New Issue
Block a user