mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-08-24 16:21:16 +02:00
Mi2: support for updating firmware fonts (*.ft, *.ft.en)
This is related to #560, but alas is not sufficient for enabling text notifications.
This commit is contained in:
parent
2b17d7fb14
commit
9411f80440
@ -89,6 +89,26 @@
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
|
||||
<data android:pathPattern="/.*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\.pbw" />
|
||||
<data android:pathPattern="/.*\\..*\\.pbw" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\.pbw" />
|
||||
@ -142,6 +162,26 @@
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
|
||||
<data android:pathPattern="/.*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft.en" />
|
||||
<data android:pathPattern="/.*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.ft" />
|
||||
<data android:pathPattern="/.*\\.pbw" />
|
||||
<data android:pathPattern="/.*\\..*\\.pbw" />
|
||||
<data android:pathPattern="/.*\\..*\\..*\\.pbw" />
|
||||
|
@ -0,0 +1,19 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2;
|
||||
|
||||
public enum FirmwareType {
|
||||
FIRMWARE((byte) 0),
|
||||
FONT((byte) 1),
|
||||
UNKNOWN1((byte) 2),
|
||||
UNKNOWN2((byte) 3),
|
||||
INVALID(Byte.MIN_VALUE);
|
||||
|
||||
private final byte value;
|
||||
|
||||
FirmwareType(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -27,13 +27,23 @@ public class Mi2FirmwareInfo {
|
||||
(byte) 0xf3,
|
||||
(byte) 0xe7,
|
||||
};
|
||||
|
||||
private static final int FW_HEADER_OFFSET = 0x150;
|
||||
|
||||
private static final byte[] FT_HEADER = new byte[] { // HMZK font file (*.ft, *.ft.xx)
|
||||
0x48,
|
||||
0x4d,
|
||||
0x5a,
|
||||
0x4b
|
||||
};
|
||||
|
||||
private static Map<Integer,String> crcToVersion = new HashMap<>();
|
||||
static {
|
||||
crcToVersion.put(41899, "1.0.0.39");
|
||||
}
|
||||
|
||||
private FirmwareType firmwareType = FirmwareType.FIRMWARE;
|
||||
|
||||
public static String toVersion(int crc16) {
|
||||
return crcToVersion.get(crc16);
|
||||
}
|
||||
@ -51,6 +61,18 @@ public class Mi2FirmwareInfo {
|
||||
this.bytes = bytes;
|
||||
crc16 = CheckSums.getCRC16(bytes);
|
||||
firmwareVersion = crcToVersion.get(crc16);
|
||||
firmwareType = determineFirmwareType(bytes);
|
||||
}
|
||||
|
||||
private FirmwareType determineFirmwareType(byte[] bytes) {
|
||||
if (ArrayUtils.startsWith(bytes, FT_HEADER)) {
|
||||
return FirmwareType.FONT;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean isGenerallyCompatibleWith(GBDevice device) {
|
||||
@ -58,8 +80,7 @@ public class Mi2FirmwareInfo {
|
||||
}
|
||||
|
||||
public boolean isHeaderValid() {
|
||||
// TODO: this is certainly not a correct validation, but it works for now
|
||||
return ArrayUtils.equals(bytes, FW_HEADER, FW_HEADER_OFFSET);
|
||||
return getFirmwareType() != FirmwareType.INVALID;
|
||||
}
|
||||
|
||||
public void checkValid() throws IllegalArgumentException {
|
||||
@ -84,4 +105,8 @@ public class Mi2FirmwareInfo {
|
||||
public int getFirmwareVersion() {
|
||||
return getCrc16(); // HACK until we know how to determine the version from the fw bytes
|
||||
}
|
||||
|
||||
public FirmwareType getFirmwareType() {
|
||||
return firmwareType;
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.AbstractMiBand2Operation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.FirmwareType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.Mi2FirmwareInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
@ -113,7 +114,12 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation {
|
||||
break;
|
||||
}
|
||||
case MiBand2Service.COMMAND_FIRMWARE_CHECKSUM: {
|
||||
sendApplyReboot(getFirmwareInfo());
|
||||
if (getFirmwareInfo().getFirmwareType() == FirmwareType.FIRMWARE) {
|
||||
getSupport().onReboot();
|
||||
} else {
|
||||
GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_update_complete), false, 100, getContext());
|
||||
done();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MiBand2Service.COMMAND_FIRMWARE_REBOOT: {
|
||||
@ -152,12 +158,20 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation {
|
||||
builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.updating_firmware), getContext()));
|
||||
int fwSize = getFirmwareInfo().getSize();
|
||||
byte[] sizeBytes = BLETypeConversions.fromUint24(fwSize);
|
||||
byte[] bytes = new byte[]{
|
||||
MiBand2Service.COMMAND_FIRMWARE_INIT,
|
||||
sizeBytes[0],
|
||||
sizeBytes[1],
|
||||
sizeBytes[2],
|
||||
};
|
||||
int arraySize = 4;
|
||||
boolean isFirmwareCode = getFirmwareInfo().getFirmwareType() == FirmwareType.FIRMWARE;
|
||||
if (!isFirmwareCode) {
|
||||
arraySize++;
|
||||
}
|
||||
byte[] bytes = new byte[arraySize];
|
||||
int i = 0;
|
||||
bytes[i++] = MiBand2Service.COMMAND_FIRMWARE_INIT;
|
||||
bytes[i++] = sizeBytes[0];
|
||||
bytes[i++] = sizeBytes[1];
|
||||
bytes[i++] = sizeBytes[2];
|
||||
if (!isFirmwareCode) {
|
||||
bytes[i++] = getFirmwareInfo().getFirmwareType().getValue();
|
||||
}
|
||||
|
||||
builder.write(fwCControlChar, bytes);
|
||||
builder.queue(getQueue());
|
||||
@ -237,12 +251,6 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation {
|
||||
builder.queue(getQueue());
|
||||
}
|
||||
|
||||
private void sendApplyReboot(Mi2FirmwareInfo firmwareInfo) throws IOException {
|
||||
TransactionBuilder builder = performInitialized("send firmware reboot");
|
||||
builder.write(fwCControlChar, new byte[] { MiBand2Service.COMMAND_FIRMWARE_REBOOT});
|
||||
builder.queue(getQueue());
|
||||
}
|
||||
|
||||
private Mi2FirmwareInfo getFirmwareInfo() {
|
||||
return firmwareInfo;
|
||||
}
|
||||
|
@ -52,4 +52,14 @@ public class ArrayUtils {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given byte array starts with the given values
|
||||
* @param array the array to check
|
||||
* @param values the values which the other array is checked to start with
|
||||
* @return
|
||||
*/
|
||||
public static boolean startsWith(byte[] array, byte[] values) {
|
||||
return equals(array, values, 0);
|
||||
}
|
||||
}
|
||||
|
@ -111,6 +111,46 @@ public class ArrayUtilsTest extends TestBase {
|
||||
assertFalse(ArrayUtils.equals(DATA_5, new byte[] {3, 4, 6}, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartsWith1() throws Exception {
|
||||
assertTrue(ArrayUtils.startsWith(DATA_5, new byte[] {1}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartsWith2() throws Exception {
|
||||
assertTrue(ArrayUtils.startsWith(DATA_5, new byte[] {1, 2}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartsWithAll() throws Exception {
|
||||
assertTrue(ArrayUtils.startsWith(DATA_5, DATA_5.clone()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartsWithEmpty() throws Exception {
|
||||
assertTrue(ArrayUtils.startsWith(DATA_5, EMPTY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartsWithFail1() throws Exception {
|
||||
try {
|
||||
ArrayUtils.startsWith(DATA_5, null);
|
||||
fail("should have thrown an exception");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartsWithFail3() throws Exception {
|
||||
assertFalse(ArrayUtils.startsWith(DATA_5, new byte[] {2, 3}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartsWithFail4() throws Exception {
|
||||
assertFalse(ArrayUtils.startsWith(DATA_5, new byte[] {1, 2, 3, 4, 5, 6}));
|
||||
}
|
||||
|
||||
private byte[] b(int b) {
|
||||
return new byte[] {(byte) b};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user