Also extracted firmware update to separate operation
This commit is contained in:
parent
dbb92b55bc
commit
99293d4ee5
|
@ -21,7 +21,6 @@ import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandFWHelper;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State;
|
||||||
|
@ -32,9 +31,8 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.FetchActivityOperation;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.FetchActivityOperation;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.UpdateFirmwareOperation;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_FLASH_COLOUR;
|
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_FLASH_COLOUR;
|
||||||
|
@ -67,11 +65,6 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||||
|
|
||||||
private DeviceInfo mDeviceInfo;
|
private DeviceInfo mDeviceInfo;
|
||||||
|
|
||||||
private boolean firmwareInfoSent = false;
|
|
||||||
private byte[] newFirmware;
|
|
||||||
private boolean rebootWhenBandReady = false;
|
|
||||||
|
|
||||||
|
|
||||||
GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
|
GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
|
||||||
|
|
||||||
public MiBandSupport() {
|
public MiBandSupport() {
|
||||||
|
@ -130,6 +123,10 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DeviceInfo getDeviceInfo() {
|
||||||
|
return mDeviceInfo;
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] getDefaultNotification() {
|
private byte[] getDefaultNotification() {
|
||||||
final int vibrateTimes = 1;
|
final int vibrateTimes = 1;
|
||||||
final long vibrateDuration = 250l;
|
final long vibrateDuration = 250l;
|
||||||
|
@ -566,19 +563,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||||
@Override
|
@Override
|
||||||
public void onInstallApp(Uri uri) {
|
public void onInstallApp(Uri uri) {
|
||||||
try {
|
try {
|
||||||
MiBandFWHelper mFwHelper = new MiBandFWHelper(uri, getContext());
|
new UpdateFirmwareOperation(uri, this).perform();
|
||||||
String mMac = getDevice().getAddress();
|
|
||||||
String[] mMacOctets = mMac.split(":");
|
|
||||||
|
|
||||||
int newFwVersion = mFwHelper.getFirmwareVersion();
|
|
||||||
int oldFwVersion = mDeviceInfo.getFirmwareVersion();
|
|
||||||
int checksum = (Integer.decode("0x" + mMacOctets[4]) << 8 | Integer.decode("0x" + mMacOctets[5])) ^ CheckSums.getCRC16(mFwHelper.getFw());
|
|
||||||
|
|
||||||
if (sendFirmwareInfo(oldFwVersion, newFwVersion, mFwHelper.getFw().length, checksum)) {
|
|
||||||
firmwareInfoSent = true;
|
|
||||||
newFirmware = mFwHelper.getFw();
|
|
||||||
//the firmware will be sent by the notification listener if the band confirms that the metadata are ok.
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
GB.toast(getContext(), "Firmware cannot be installed: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR);
|
GB.toast(getContext(), "Firmware cannot be installed: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR);
|
||||||
}
|
}
|
||||||
|
@ -681,43 +666,13 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (value[0]) {
|
switch (value[0]) {
|
||||||
case MiBandService.NOTIFY_FW_CHECK_SUCCESS:
|
|
||||||
if(firmwareInfoSent && newFirmware != null) {
|
|
||||||
if(sendFirmwareData(newFirmware)) {
|
|
||||||
rebootWhenBandReady = true;
|
|
||||||
} else {
|
|
||||||
//TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do?
|
|
||||||
GB.toast("Problem with the firmware transfer. DO NOT REBOOT YOUR MIBAND!!!", Toast.LENGTH_LONG, GB.ERROR);
|
|
||||||
}
|
|
||||||
firmwareInfoSent = false;
|
|
||||||
newFirmware = null;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MiBandService.NOTIFY_FW_CHECK_FAILED:
|
|
||||||
GB.toast("Problem with the firmware metadata transfer", Toast.LENGTH_LONG, GB.ERROR);
|
|
||||||
firmwareInfoSent = false;
|
|
||||||
newFirmware = null;
|
|
||||||
break;
|
|
||||||
case MiBandService.NOTIFY_FIRMWARE_UPDATE_SUCCESS:
|
|
||||||
if (rebootWhenBandReady) {
|
|
||||||
GB.updateInstallNotification("Firmware installation complete", false, 100, getContext());
|
|
||||||
onReboot();
|
|
||||||
}
|
|
||||||
rebootWhenBandReady = false;
|
|
||||||
break;
|
|
||||||
case MiBandService.NOTIFY_FIRMWARE_UPDATE_FAILED:
|
|
||||||
//TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do?
|
|
||||||
GB.toast("Problem with the firmware transfer. DO NOT REBOOT YOUR MIBAND!!!", Toast.LENGTH_LONG, GB.ERROR);
|
|
||||||
GB.updateInstallNotification("Firmware write failed", false, 0, getContext());
|
|
||||||
rebootWhenBandReady = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
for (byte b : value) {
|
for (byte b : value) {
|
||||||
LOG.warn("DATA: " + String.format("0x%2x", b));
|
LOG.warn("DATA: " + String.format("0x%2x", b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDeviceInfo(byte[] value, int status) {
|
private void handleDeviceInfo(byte[] value, int status) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
mDeviceInfo = new DeviceInfo(value);
|
mDeviceInfo = new DeviceInfo(value);
|
||||||
|
@ -818,103 +773,4 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||||
}
|
}
|
||||||
LOG.info("MI Band pairing result: " + value);
|
LOG.info("MI Band pairing result: " + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
* the actual firmare.
|
|
||||||
*
|
|
||||||
* The Mi Band will send a notification after receiving these data to confirm if the metadata looks good to it.
|
|
||||||
* @see MiBandSupport#handleNotificationNotif
|
|
||||||
*
|
|
||||||
* @param currentFwVersion
|
|
||||||
* @param newFwVersion
|
|
||||||
* @param newFwSize
|
|
||||||
* @param checksum
|
|
||||||
* @return whether the transfer succeeded or not. Only a BT layer exception will cause the transmission to fail.
|
|
||||||
*/
|
|
||||||
private boolean sendFirmwareInfo(int currentFwVersion, int newFwVersion, int newFwSize, int checksum) {
|
|
||||||
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)
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
TransactionBuilder builder = performInitialized("send firmware info");
|
|
||||||
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), fwInfo);
|
|
||||||
builder.queue(getQueue());
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOG.error("Unable to send fwInfo to MI", ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method that uploads a firmware (fwbytes) to the MiBand.
|
|
||||||
* The firmware has to be splitted into chunks of 20 bytes each, and periodically a COMMAND_SYNC comand has to be issued to the MiBand.
|
|
||||||
*
|
|
||||||
* The Mi Band will send a notification after receiving these data to confirm if the firmware looks good to it.
|
|
||||||
* @see MiBandSupport#handleNotificationNotif
|
|
||||||
*
|
|
||||||
* @param fwbytes
|
|
||||||
* @return whether the transfer succeeded or not. Only a BT layer exception will cause the transmission to fail.
|
|
||||||
* */
|
|
||||||
private boolean sendFirmwareData(byte fwbytes[]) {
|
|
||||||
int len = fwbytes.length;
|
|
||||||
final int packetLength = 20;
|
|
||||||
int packets = len / packetLength;
|
|
||||||
byte fwChunk[] = new byte[packetLength];
|
|
||||||
|
|
||||||
int firmwareProgress = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
TransactionBuilder builder = performInitialized("send firmware packet");
|
|
||||||
for (int i = 0; i < packets; i++) {
|
|
||||||
fwChunk = Arrays.copyOfRange(fwbytes, i * packetLength, i * packetLength + packetLength);
|
|
||||||
|
|
||||||
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_FIRMWARE_DATA), fwChunk);
|
|
||||||
firmwareProgress += packetLength;
|
|
||||||
|
|
||||||
if ((i > 0) && (i % 50 == 0)) {
|
|
||||||
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), new byte[]{MiBandService.COMMAND_SYNC});
|
|
||||||
builder.add(new SetProgressAction("Firmware update in progress", true, (firmwareProgress / len) * 100, getContext()));
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.info("Firmware update progress:" + firmwareProgress + " total len:" + len + " progress:" + (firmwareProgress / len));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(len % packetLength == 0)) {
|
|
||||||
byte lastChunk[] = new byte[len % packetLength];
|
|
||||||
lastChunk = Arrays.copyOfRange(fwbytes, packets * packetLength, len);
|
|
||||||
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_FIRMWARE_DATA), lastChunk);
|
|
||||||
firmwareProgress += len % packetLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.info("Firmware update progress:" + firmwareProgress + " total len:" + len + " progress:" + (firmwareProgress / len));
|
|
||||||
if (firmwareProgress >= len) {
|
|
||||||
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), new byte[]{MiBandService.COMMAND_SYNC});
|
|
||||||
} else {
|
|
||||||
GB.updateInstallNotification("Firmware write failed", false, 0, getContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.queue(getQueue());
|
|
||||||
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOG.error("Unable to send fw to MI", ex);
|
|
||||||
GB.updateInstallNotification("Firmware write failed", false, 0, getContext());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,215 @@
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothGatt;
|
||||||
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandFWHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEOperation;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
|
public class UpdateFirmwareOperation extends AbstractBTLEOperation<MiBandSupport> {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(UpdateFirmwareOperation.class);
|
||||||
|
|
||||||
|
private final Uri uri;
|
||||||
|
private boolean firmwareInfoSent = false;
|
||||||
|
private byte[] newFirmware;
|
||||||
|
private boolean rebootWhenBandReady = false;
|
||||||
|
|
||||||
|
public UpdateFirmwareOperation(Uri uri, MiBandSupport support) {
|
||||||
|
super(support);
|
||||||
|
this.uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void perform() throws IOException {
|
||||||
|
MiBandFWHelper mFwHelper = new MiBandFWHelper(uri, getContext());
|
||||||
|
String mMac = getDevice().getAddress();
|
||||||
|
String[] mMacOctets = mMac.split(":");
|
||||||
|
|
||||||
|
int newFwVersion = mFwHelper.getFirmwareVersion();
|
||||||
|
int oldFwVersion = getSupport().getDeviceInfo().getFirmwareVersion();
|
||||||
|
int checksum = (Integer.decode("0x" + mMacOctets[4]) << 8 | Integer.decode("0x" + mMacOctets[5])) ^ CheckSums.getCRC16(mFwHelper.getFw());
|
||||||
|
|
||||||
|
sendFirmwareInfo(oldFwVersion, newFwVersion, mFwHelper.getFw().length, checksum);
|
||||||
|
firmwareInfoSent = true;
|
||||||
|
newFirmware = mFwHelper.getFw();
|
||||||
|
//the firmware will be sent by the notification listener if the band confirms that the metadata are ok.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCharacteristicChanged(BluetoothGatt gatt,
|
||||||
|
BluetoothGattCharacteristic characteristic) {
|
||||||
|
super.onCharacteristicChanged(gatt, characteristic);
|
||||||
|
|
||||||
|
UUID characteristicUUID = characteristic.getUuid();
|
||||||
|
if (MiBandService.UUID_CHARACTERISTIC_NOTIFICATION.equals(characteristicUUID)) {
|
||||||
|
handleNotificationNotif(characteristic.getValue());
|
||||||
|
} else {
|
||||||
|
super.onCharacteristicChanged(gatt, characteristic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React to unsolicited messages sent by the Mi Band to the MiBandService.UUID_CHARACTERISTIC_NOTIFICATION
|
||||||
|
* characteristic,
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Upon receiving known values that request further action by GB, the appropriate method is called.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
private void handleNotificationNotif(byte[] value) {
|
||||||
|
if(value.length != 1) {
|
||||||
|
LOG.error("Notifications should be 1 byte long.");
|
||||||
|
LOG.info("RECEIVED DATA WITH LENGTH: " + value.length);
|
||||||
|
for (byte b : value) {
|
||||||
|
LOG.warn("DATA: " + String.format("0x%2x", b));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (value[0]) {
|
||||||
|
case MiBandService.NOTIFY_FW_CHECK_SUCCESS:
|
||||||
|
if(firmwareInfoSent && newFirmware != null) {
|
||||||
|
if(sendFirmwareData(newFirmware)) {
|
||||||
|
rebootWhenBandReady = true;
|
||||||
|
} else {
|
||||||
|
//TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do?
|
||||||
|
GB.toast("Problem with the firmware transfer. DO NOT REBOOT YOUR MIBAND!!!", Toast.LENGTH_LONG, GB.ERROR);
|
||||||
|
}
|
||||||
|
firmwareInfoSent = false;
|
||||||
|
newFirmware = null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MiBandService.NOTIFY_FW_CHECK_FAILED:
|
||||||
|
GB.toast("Problem with the firmware metadata transfer", Toast.LENGTH_LONG, GB.ERROR);
|
||||||
|
firmwareInfoSent = false;
|
||||||
|
newFirmware = null;
|
||||||
|
break;
|
||||||
|
case MiBandService.NOTIFY_FIRMWARE_UPDATE_SUCCESS:
|
||||||
|
if (rebootWhenBandReady) {
|
||||||
|
GB.updateInstallNotification("Firmware installation complete", false, 100, getContext());
|
||||||
|
getSupport().onReboot();
|
||||||
|
}
|
||||||
|
rebootWhenBandReady = false;
|
||||||
|
break;
|
||||||
|
case MiBandService.NOTIFY_FIRMWARE_UPDATE_FAILED:
|
||||||
|
//TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do?
|
||||||
|
GB.toast("Problem with the firmware transfer. DO NOT REBOOT YOUR MIBAND!!!", Toast.LENGTH_LONG, GB.ERROR);
|
||||||
|
GB.updateInstallNotification("Firmware write failed", false, 0, getContext());
|
||||||
|
rebootWhenBandReady = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
for (byte b : value) {
|
||||||
|
LOG.warn("DATA: " + String.format("0x%2x", b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* the actual firmare.
|
||||||
|
*
|
||||||
|
* The Mi Band will send a notification after receiving these data to confirm if the metadata looks good to it.
|
||||||
|
* @see MiBandSupport#handleNotificationNotif
|
||||||
|
*
|
||||||
|
* @param currentFwVersion
|
||||||
|
* @param newFwVersion
|
||||||
|
* @param newFwSize
|
||||||
|
* @param checksum
|
||||||
|
*/
|
||||||
|
private void sendFirmwareInfo(int currentFwVersion, int newFwVersion, int newFwSize, int checksum) throws IOException {
|
||||||
|
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)
|
||||||
|
};
|
||||||
|
TransactionBuilder builder = performInitialized("send firmware info");
|
||||||
|
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), fwInfo);
|
||||||
|
builder.queue(getQueue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that uploads a firmware (fwbytes) to the MiBand.
|
||||||
|
* The firmware has to be splitted into chunks of 20 bytes each, and periodically a COMMAND_SYNC comand has to be issued to the MiBand.
|
||||||
|
*
|
||||||
|
* The Mi Band will send a notification after receiving these data to confirm if the firmware looks good to it.
|
||||||
|
* @see MiBandSupport#handleNotificationNotif
|
||||||
|
*
|
||||||
|
* @param fwbytes
|
||||||
|
* @return whether the transfer succeeded or not. Only a BT layer exception will cause the transmission to fail.
|
||||||
|
* */
|
||||||
|
private boolean sendFirmwareData(byte fwbytes[]) {
|
||||||
|
int len = fwbytes.length;
|
||||||
|
final int packetLength = 20;
|
||||||
|
int packets = len / packetLength;
|
||||||
|
byte fwChunk[] = new byte[packetLength];
|
||||||
|
|
||||||
|
int firmwareProgress = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
TransactionBuilder builder = performInitialized("send firmware packet");
|
||||||
|
for (int i = 0; i < packets; i++) {
|
||||||
|
fwChunk = Arrays.copyOfRange(fwbytes, i * packetLength, i * packetLength + packetLength);
|
||||||
|
|
||||||
|
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_FIRMWARE_DATA), fwChunk);
|
||||||
|
firmwareProgress += packetLength;
|
||||||
|
|
||||||
|
if ((i > 0) && (i % 50 == 0)) {
|
||||||
|
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), new byte[]{MiBandService.COMMAND_SYNC});
|
||||||
|
builder.add(new SetProgressAction("Firmware update in progress", true, (firmwareProgress / len) * 100, getContext()));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.info("Firmware update progress:" + firmwareProgress + " total len:" + len + " progress:" + (firmwareProgress / len));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(len % packetLength == 0)) {
|
||||||
|
byte lastChunk[] = new byte[len % packetLength];
|
||||||
|
lastChunk = Arrays.copyOfRange(fwbytes, packets * packetLength, len);
|
||||||
|
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_FIRMWARE_DATA), lastChunk);
|
||||||
|
firmwareProgress += len % packetLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.info("Firmware update progress:" + firmwareProgress + " total len:" + len + " progress:" + (firmwareProgress / len));
|
||||||
|
if (firmwareProgress >= len) {
|
||||||
|
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), new byte[]{MiBandService.COMMAND_SYNC});
|
||||||
|
} else {
|
||||||
|
GB.updateInstallNotification("Firmware write failed", false, 0, getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.queue(getQueue());
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.error("Unable to send fw to MI", ex);
|
||||||
|
GB.updateInstallNotification("Firmware write failed", false, 0, getContext());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue