Amazfit Bip: Initial experimental firmware update support

USE AT YOUR OWN RISK:

NOTE: During update your device is named a Mi Band

1) Flash .gps (installation will take a while after transfer)
2) Flash .res
3) Flash .fw (device will reboot)
4) Gadgetbridge wont notice that update was successfull, known bug.
This commit is contained in:
Andreas Shimokawa 2017-08-25 00:21:47 +02:00
parent ebc1cedf55
commit 12d9b7812f
8 changed files with 235 additions and 11 deletions

View File

@ -52,10 +52,9 @@ public class AmazfitBipCooordinator extends MiBand2Coordinator {
return DeviceType.UNKNOWN;
}
@Override
public InstallHandler findInstallHandler(Uri uri, Context context) {
return null; // not supported yet
AmazfitBipFWInstallHandler handler = new AmazfitBipFWInstallHandler(uri, context);
return handler.isValid() ? handler : null;
}
}

View File

@ -0,0 +1,90 @@
/* Copyright (C) 2016-2017 Carsten Pfeiffer
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 <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import java.io.IOException;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.AbstractMiBandFWHelper;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.AmazfitBipFirmwareInfo;
public class AmazfitBipFWHelper extends AbstractMiBandFWHelper {
public AmazfitBipFWHelper(Uri uri, Context context) throws IOException {
super(uri, context);
}
private AmazfitBipFirmwareInfo firmwareInfo;
@Override
public String format(int version) {
return AmazfitBipFirmwareInfo.toVersion(version);
}
@Override
public int getFirmwareVersion() {
return firmwareInfo.getFirmwareVersion();
}
@Override
public int getFirmware2Version() {
return 0;
}
@Override
public String getHumanFirmwareVersion2() {
return "";
}
@Override
protected int[] getWhitelistedFirmwareVersions() {
return AmazfitBipFirmwareInfo.getWhitelistedVersions();
}
@Override
public boolean isFirmwareGenerallyCompatibleWith(GBDevice device) {
return firmwareInfo.isGenerallyCompatibleWith(device);
}
@Override
public boolean isSingleFirmware() {
return true;
}
@NonNull
@Override
protected void determineFirmwareInfo(byte[] wholeFirmwareBytes) {
firmwareInfo = new AmazfitBipFirmwareInfo(wholeFirmwareBytes);
if (!firmwareInfo.isHeaderValid()) {
throw new IllegalArgumentException("Not a an Amazifit Bip firmware");
}
}
@Override
public void checkValid() throws IllegalArgumentException {
firmwareInfo.checkValid();
}
public AmazfitBipFirmwareInfo getFirmwareInfo() {
return firmwareInfo;
}
}

View File

@ -0,0 +1,43 @@
/* Copyright (C) 2016-2017 Carsten Pfeiffer
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 <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip;
import android.content.Context;
import android.net.Uri;
import java.io.IOException;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.AbstractMiBandFWHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.AbstractMiBandFWInstallHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
class AmazfitBipFWInstallHandler extends AbstractMiBandFWInstallHandler {
AmazfitBipFWInstallHandler(Uri uri, Context context) {
super(uri, context);
}
@Override
protected AbstractMiBandFWHelper createHelper(Uri uri, Context context) throws IOException {
return new AmazfitBipFWHelper(uri, context);
}
@Override
protected boolean isSupportedDeviceType(GBDevice device) {
return device.getType() == DeviceType.AMAZFITBIP;
}
}

View File

@ -0,0 +1,79 @@
/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
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 <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.FirmwareType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.Mi2FirmwareInfo;
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
public class AmazfitBipFirmwareInfo extends Mi2FirmwareInfo {
// total crap maybe
private static final byte[] GPS_HEADER = new byte[]{
(byte) 0xcb, 0x51, (byte) 0xc1, 0x30, 0x41, (byte) 0x9e, 0x5e, (byte) 0xd3,
0x51, 0x35, (byte) 0xdf, 0x66, (byte) 0xed, (byte) 0xd9, 0x5f, (byte) 0xa7
};
// guessed - at least it is the same accross current versions and different from other devices
private static final byte[] FW_HEADER = new byte[]{
0x3f, 0x34, 0x00, 0x20, 0x27, 0x35, 0x00, 0x20,
0x0d, 0x31, 0x03, 0x00, 0x15, 0x35, 0x00, 0x20
};
private static final int FW_HEADER_OFFSET = 0x40;
private static final byte[] RES_HEADER = new byte[]{ // HMRES resources file (*.res)
0x48, 0x4d, 0x52, 0x45, 0x53
};
static {
// firmware
crcToVersion.put(25257, "0.0.8.74");
// resources
crcToVersion.put(12586, "0.0.8.74 (RES)");
// gps
}
public AmazfitBipFirmwareInfo(byte[] bytes) {
super(bytes);
}
@Override
protected FirmwareType determineFirmwareType(byte[] bytes) {
if (ArrayUtils.startsWith(bytes, RES_HEADER)) {
return FirmwareType.RES;
}
if (ArrayUtils.startsWith(bytes, GPS_HEADER)) {
return FirmwareType.GPS;
}
if (ArrayUtils.equals(bytes, FW_HEADER, FW_HEADER_OFFSET)) {
// TODO: this is certainly not a correct validation, but it works for now
return FirmwareType.FIRMWARE;
}
return FirmwareType.INVALID;
}
@Override
public boolean isGenerallyCompatibleWith(GBDevice device) {
return isHeaderValid() && device.getType() == DeviceType.AMAZFITBIP;
}
}

View File

@ -16,6 +16,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip;
import android.net.Uri;
import android.widget.Toast;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -35,8 +38,10 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.NewAlert;
import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.operations.AmazfitBipUpdateFirmwareOperation;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
public class AmazfitBipSupport extends MiBand2Support {
@ -113,6 +118,14 @@ public class AmazfitBipSupport extends MiBand2Support {
}
@Override
public void onInstallApp(Uri uri) {
try {
new AmazfitBipUpdateFirmwareOperation(uri, this).perform();
} catch (IOException ex) {
GB.toast(getContext(), "Firmware cannot be installed: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex);
}
}
public void onSendWeather(WeatherSpec weatherSpec) {
try {
TransactionBuilder builder = performInitialized("Sending weather forecast");

View File

@ -19,8 +19,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2;
public enum FirmwareType {
FIRMWARE((byte) 0),
FONT((byte) 1),
UNKNOWN1((byte) 2),
UNKNOWN2((byte) 3),
RES((byte) 2),
GPS((byte) 3),
INVALID(Byte.MIN_VALUE);
private final byte value;

View File

@ -53,7 +53,7 @@ public class Mi2FirmwareInfo {
0x4b
};
private static Map<Integer,String> crcToVersion = new HashMap<>();
protected static Map<Integer,String> crcToVersion = new HashMap<>();
static {
// firmware
crcToVersion.put(41899, "1.0.0.39");
@ -89,7 +89,7 @@ public class Mi2FirmwareInfo {
firmwareType = determineFirmwareType(bytes);
}
private FirmwareType determineFirmwareType(byte[] bytes) {
protected FirmwareType determineFirmwareType(byte[] bytes) {
if (ArrayUtils.startsWith(bytes, FT_HEADER)) {
return FirmwareType.FONT;
}

View File

@ -49,10 +49,10 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation {
private static final Logger LOG = LoggerFactory.getLogger(UpdateFirmwareOperation.class);
private final Uri uri;
private final BluetoothGattCharacteristic fwCControlChar;
private final BluetoothGattCharacteristic fwCDataChar;
final Prefs prefs = GBApplication.getPrefs();
private Mi2FirmwareInfo firmwareInfo;
protected final BluetoothGattCharacteristic fwCControlChar;
protected final BluetoothGattCharacteristic fwCDataChar;
protected final Prefs prefs = GBApplication.getPrefs();
protected Mi2FirmwareInfo firmwareInfo;
public UpdateFirmwareOperation(Uri uri, MiBand2Support support) {
super(support);