mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
CMF Watch Pro: Firmware update
Tested by updating to 11.0.0.57
This commit is contained in:
+20
-14
@@ -473,8 +473,10 @@ public class BleNamesResolver {
|
|||||||
mServices.put("16187f00-0000-1000-8000-00807f9b34fb", "(Propr: Xiaomi Wear Service - Mi Smart Watch 4C/Redmi Band)");
|
mServices.put("16187f00-0000-1000-8000-00807f9b34fb", "(Propr: Xiaomi Wear Service - Mi Smart Watch 4C/Redmi Band)");
|
||||||
mServices.put("1314f000-1000-9000-7000-301291e21220", "(Propr: Xiaomi Wear Service - Mi Watch/Mi Watch Color/Mi Watch Color Sport)");
|
mServices.put("1314f000-1000-9000-7000-301291e21220", "(Propr: Xiaomi Wear Service - Mi Watch/Mi Watch Color/Mi Watch Color Sport)");
|
||||||
mServices.put("7495fe00-a7f3-424b-92dd-4a006a3aef56", "(Propr: Xiaomi Wear Service - Mi Watch CN)");
|
mServices.put("7495fe00-a7f3-424b-92dd-4a006a3aef56", "(Propr: Xiaomi Wear Service - Mi Watch CN)");
|
||||||
//mServices.put("0000fff0-0000-1000-8000-00805f9b34fb", "(Propr: Nothing CMF Command");
|
mServices.put("0000fff0-0000-1000-8000-00805f9b34fb", "(Propr: Nothing CMF Command");
|
||||||
//mServices.put("02f00000-0000-0000-0000-00000000ffe0", "(Propr: Nothing CMF Data");
|
mServices.put("02f00000-0000-0000-0000-00000000ffe0", "(Propr: Nothing CMF Data");
|
||||||
|
mServices.put("02f00000-0000-0000-0000-00000000fe00", "(Propr: Nothing CMF Firmware");
|
||||||
|
mServices.put("77d4e67c-2fe2-2334-0d35-9ccd078f529c", "(Propr: Nothing CMF Shell");
|
||||||
mServices.put("9b012401-bc30-ce9a-e111-0f67e491abde", "(Propr: Garmin GFDI V0)");
|
mServices.put("9b012401-bc30-ce9a-e111-0f67e491abde", "(Propr: Garmin GFDI V0)");
|
||||||
mServices.put("6a4e2401-667b-11e3-949a-0800200c9a66", "(Propr: Garmin GFDI V1)");
|
mServices.put("6a4e2401-667b-11e3-949a-0800200c9a66", "(Propr: Garmin GFDI V1)");
|
||||||
mServices.put("6a4e2800-667b-11e3-949a-0800200c9a66", "(Propr: Garmin ML)");
|
mServices.put("6a4e2800-667b-11e3-949a-0800200c9a66", "(Propr: Garmin ML)");
|
||||||
@@ -972,18 +974,22 @@ public class BleNamesResolver {
|
|||||||
mCharacteristics.put("6a4e2823-667b-11e3-949a-0800200c9a66", "(Propr: Garmin ML 3 TX)");
|
mCharacteristics.put("6a4e2823-667b-11e3-949a-0800200c9a66", "(Propr: Garmin ML 3 TX)");
|
||||||
mCharacteristics.put("6a4e2814-667b-11e3-949a-0800200c9a66", "(Propr: Garmin ML 4 RX)");
|
mCharacteristics.put("6a4e2814-667b-11e3-949a-0800200c9a66", "(Propr: Garmin ML 4 RX)");
|
||||||
mCharacteristics.put("6a4e2824-667b-11e3-949a-0800200c9a66", "(Propr: Garmin ML 4 TX)");
|
mCharacteristics.put("6a4e2824-667b-11e3-949a-0800200c9a66", "(Propr: Garmin ML 4 TX)");
|
||||||
//mCharacteristics.put("0000fff1-0000-1000-8000-00805f9b34fb", "(Propr: Nothing CMF Command Read");
|
mCharacteristics.put("0000fff1-0000-1000-8000-00805f9b34fb", "(Propr: Nothing CMF Command Read");
|
||||||
//mCharacteristics.put("0000fff2-0000-1000-8000-00805f9b34fb", "(Propr: Nothing CMF Command Write");
|
mCharacteristics.put("0000fff2-0000-1000-8000-00805f9b34fb", "(Propr: Nothing CMF Command Write");
|
||||||
//mCharacteristics.put("02f00000-0000-0000-0000-00000000ffe1", "(Propr: Nothing CMF Data Write");
|
mCharacteristics.put("02f00000-0000-0000-0000-00000000ffe1", "(Propr: Nothing CMF Data Write");
|
||||||
//mCharacteristics.put("02f00000-0000-0000-0000-00000000ffe2", "(Propr: Nothing CMF Data Read");
|
mCharacteristics.put("02f00000-0000-0000-0000-00000000ffe2", "(Propr: Nothing CMF Data Read");
|
||||||
//mCharacteristics.put("00010203-0405-0607-0809-0a0b0c0d2b12", "(Propr: Telink OTA Write)");
|
mCharacteristics.put("77d4ff01-2fe2-2334-0d35-9ccd078f529c", "(Propr: Nothing CMF Shell Write");
|
||||||
//mCharacteristics.put("ebe0ccb7-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd TIME)");
|
mCharacteristics.put("77d4ff02-2fe2-2334-0d35-9ccd078f529c", "(Propr: Nothing CMF Shell Read");
|
||||||
//mCharacteristics.put("ebe0ccc4-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd BATTERY)");
|
mCharacteristics.put("02f00000-0000-0000-0000-00000000ff01", "(Propr: Nothing CMF Firmware Write");
|
||||||
//mCharacteristics.put("ebe0ccbe-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd TEMPERATURE_UNIT)");
|
mCharacteristics.put("02f00000-0000-0000-0000-00000000ff02", "(Propr: Nothing CMF Firmware Read");
|
||||||
//mCharacteristics.put("ebe0ccd8-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd CONN_INTERVAL)");
|
mCharacteristics.put("00010203-0405-0607-0809-0a0b0c0d2b12", "(Propr: Telink OTA Write)");
|
||||||
//mCharacteristics.put("ebe0ccbc-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd HISTORY)");
|
mCharacteristics.put("ebe0ccb7-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd TIME)");
|
||||||
//mCharacteristics.put("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd LIVE_DATA)");
|
mCharacteristics.put("ebe0ccc4-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd BATTERY)");
|
||||||
//mCharacteristics.put("ebe0ccba-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd HISTORY_LAST_ID)");
|
mCharacteristics.put("ebe0ccbe-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd TEMPERATURE_UNIT)");
|
||||||
|
mCharacteristics.put("ebe0ccd8-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd CONN_INTERVAL)");
|
||||||
|
mCharacteristics.put("ebe0ccbc-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd HISTORY)");
|
||||||
|
mCharacteristics.put("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd LIVE_DATA)");
|
||||||
|
mCharacteristics.put("ebe0ccba-7a0a-4b0c-8a1a-6ff2997da3a6", "(Propr: Lywsd HISTORY_LAST_ID)");
|
||||||
mCharacteristics.put("00000001-0000-3512-2118-0009af100700", "(Propr: Huami Raw Sensor Control)");
|
mCharacteristics.put("00000001-0000-3512-2118-0009af100700", "(Propr: Huami Raw Sensor Control)");
|
||||||
mCharacteristics.put("00000002-0000-3512-2118-0009af100700", "(Propr: Huami Raw Sensor Data)");
|
mCharacteristics.put("00000002-0000-3512-2118-0009af100700", "(Propr: Huami Raw Sensor Data)");
|
||||||
mCharacteristics.put("00000003-0000-3512-2118-0009af100700", "(Propr: Huami Configuration)");
|
mCharacteristics.put("00000003-0000-3512-2118-0009af100700", "(Propr: Huami Configuration)");
|
||||||
|
|||||||
+1
@@ -185,6 +185,7 @@ public class CmfCharacteristic {
|
|||||||
case AUTH_PAIR_REQUEST:
|
case AUTH_PAIR_REQUEST:
|
||||||
case AUTH_PAIR_REPLY:
|
case AUTH_PAIR_REPLY:
|
||||||
case DATA_CHUNK_WRITE_AGPS:
|
case DATA_CHUNK_WRITE_AGPS:
|
||||||
|
case DATA_CHUNK_WRITE_FIRMWARE:
|
||||||
case DATA_CHUNK_WRITE_WATCHFACE:
|
case DATA_CHUNK_WRITE_WATCHFACE:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -42,13 +42,21 @@ public enum CmfCommand {
|
|||||||
CONTACTS_GET(0x00d5, 0x0002),
|
CONTACTS_GET(0x00d5, 0x0002),
|
||||||
CONTACTS_SET(0x00d5, 0x0001),
|
CONTACTS_SET(0x00d5, 0x0001),
|
||||||
DATA_CHUNK_REQUEST_AGPS(0xffff, 0xa05f),
|
DATA_CHUNK_REQUEST_AGPS(0xffff, 0xa05f),
|
||||||
|
DATA_CHUNK_REQUEST_FIRMWARE(0xffff, 0xa042),
|
||||||
DATA_CHUNK_REQUEST_WATCHFACE(0xffff, 0xa064),
|
DATA_CHUNK_REQUEST_WATCHFACE(0xffff, 0xa064),
|
||||||
DATA_CHUNK_WRITE_AGPS(0xffff, 0x905f),
|
DATA_CHUNK_WRITE_AGPS(0xffff, 0x905f),
|
||||||
|
DATA_CHUNK_WRITE_FIRMWARE(0xffff, 0x9042),
|
||||||
DATA_CHUNK_WRITE_WATCHFACE(0xffff, 0x9064),
|
DATA_CHUNK_WRITE_WATCHFACE(0xffff, 0x9064),
|
||||||
DATA_TRANSFER_AGPS_FINISH_ACK_1(0xffff, 0xa060),
|
DATA_TRANSFER_AGPS_FINISH_ACK_1(0xffff, 0xa060),
|
||||||
DATA_TRANSFER_AGPS_FINISH_ACK_2(0xffff, 0x9060),
|
DATA_TRANSFER_AGPS_FINISH_ACK_2(0xffff, 0x9060),
|
||||||
DATA_TRANSFER_AGPS_INIT_REPLY(0xffff, 0xa05e),
|
DATA_TRANSFER_AGPS_INIT_REPLY(0xffff, 0xa05e),
|
||||||
DATA_TRANSFER_AGPS_INIT_REQUEST(0xffff, 0x905e),
|
DATA_TRANSFER_AGPS_INIT_REQUEST(0xffff, 0x905e),
|
||||||
|
DATA_TRANSFER_FIRMWARE_INIT_1_REQUEST(0xffff, 0x9052),
|
||||||
|
DATA_TRANSFER_FIRMWARE_INIT_1_REPLY(0xffff, 0xa052),
|
||||||
|
DATA_TRANSFER_FIRMWARE_INIT_2_REQUEST(0xffff, 0x9040),
|
||||||
|
DATA_TRANSFER_FIRMWARE_INIT_2_REPLY(0xffff, 0xa040),
|
||||||
|
DATA_TRANSFER_FIRMWARE_FINISH_ACK_1(0xffff, 0xa041),
|
||||||
|
DATA_TRANSFER_FIRMWARE_FINISH_ACK_2(0xffff, 0x9041),
|
||||||
DATA_TRANSFER_WATCHFACE_FINISH_ACK_1(0xffff, 0xa065),
|
DATA_TRANSFER_WATCHFACE_FINISH_ACK_1(0xffff, 0xa065),
|
||||||
DATA_TRANSFER_WATCHFACE_FINISH_ACK_2(0xffff, 0x9065),
|
DATA_TRANSFER_WATCHFACE_FINISH_ACK_2(0xffff, 0x9065),
|
||||||
DATA_TRANSFER_WATCHFACE_INIT_1_REQUEST(0xffff, 0x8052),
|
DATA_TRANSFER_WATCHFACE_INIT_1_REQUEST(0xffff, 0x8052),
|
||||||
|
|||||||
+61
-6
@@ -45,7 +45,7 @@ public class CmfDataUploader implements CmfCharacteristic.Handler {
|
|||||||
@Override
|
@Override
|
||||||
public void onCommand(final CmfCommand cmd, final byte[] payload) {
|
public void onCommand(final CmfCommand cmd, final byte[] payload) {
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case DATA_TRANSFER_WATCHFACE_INIT_1_REPLY:
|
case DATA_TRANSFER_WATCHFACE_INIT_1_REPLY: {
|
||||||
if (payload[0] != 0x01) {
|
if (payload[0] != 0x01) {
|
||||||
LOG.warn("Got unexpected transfer init 1 reply {}", payload[0]);
|
LOG.warn("Got unexpected transfer init 1 reply {}", payload[0]);
|
||||||
fwHelper = null;
|
fwHelper = null;
|
||||||
@@ -63,7 +63,30 @@ public class CmfDataUploader implements CmfCharacteristic.Handler {
|
|||||||
buf.array()
|
buf.array()
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
case DATA_TRANSFER_FIRMWARE_INIT_1_REPLY: {
|
||||||
|
if (payload[0] != 0x01) {
|
||||||
|
LOG.warn("Got unexpected firmware init 2 reply {}", payload[0]);
|
||||||
|
fwHelper = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ByteBuffer buf = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
|
||||||
|
// FIXME version a.b.c.d... how to know? this was from 11.0.0.57
|
||||||
|
buf.put((byte) (0x0b));
|
||||||
|
buf.put((byte) (0x00));
|
||||||
|
buf.put((byte) (0x00));
|
||||||
|
buf.put((byte) (0x39));
|
||||||
|
|
||||||
|
mSupport.sendFirmware(
|
||||||
|
"transfer firmware init request",
|
||||||
|
CmfCommand.DATA_TRANSFER_FIRMWARE_INIT_2_REQUEST,
|
||||||
|
buf.array()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
case DATA_TRANSFER_AGPS_INIT_REPLY:
|
case DATA_TRANSFER_AGPS_INIT_REPLY:
|
||||||
|
case DATA_TRANSFER_FIRMWARE_INIT_2_REPLY:
|
||||||
case DATA_TRANSFER_WATCHFACE_INIT_2_REPLY:
|
case DATA_TRANSFER_WATCHFACE_INIT_2_REPLY:
|
||||||
if (payload[0] != 0x01) {
|
if (payload[0] != 0x01) {
|
||||||
LOG.warn("Got unexpected transfer 2 init reply {}", payload[0]);
|
LOG.warn("Got unexpected transfer 2 init reply {}", payload[0]);
|
||||||
@@ -78,6 +101,11 @@ public class CmfDataUploader implements CmfCharacteristic.Handler {
|
|||||||
case DATA_TRANSFER_WATCHFACE_FINISH_ACK_1:
|
case DATA_TRANSFER_WATCHFACE_FINISH_ACK_1:
|
||||||
handleAck1(CmfCommand.DATA_TRANSFER_WATCHFACE_FINISH_ACK_2, payload);
|
handleAck1(CmfCommand.DATA_TRANSFER_WATCHFACE_FINISH_ACK_2, payload);
|
||||||
return;
|
return;
|
||||||
|
case DATA_TRANSFER_FIRMWARE_FINISH_ACK_1:
|
||||||
|
// TODO: Confirm if this is being sent in the right characteristic, although it looks
|
||||||
|
// like it does not matter, since it restarts right away
|
||||||
|
handleAck1(CmfCommand.DATA_TRANSFER_FIRMWARE_FINISH_ACK_2, payload);
|
||||||
|
return;
|
||||||
case DATA_TRANSFER_AGPS_FINISH_ACK_1:
|
case DATA_TRANSFER_AGPS_FINISH_ACK_1:
|
||||||
handleAck1(CmfCommand.DATA_TRANSFER_AGPS_FINISH_ACK_2, payload);
|
handleAck1(CmfCommand.DATA_TRANSFER_AGPS_FINISH_ACK_2, payload);
|
||||||
return;
|
return;
|
||||||
@@ -95,6 +123,13 @@ public class CmfDataUploader implements CmfCharacteristic.Handler {
|
|||||||
}
|
}
|
||||||
handleChunkRequest(CmfCommand.DATA_CHUNK_WRITE_WATCHFACE, payload);
|
handleChunkRequest(CmfCommand.DATA_CHUNK_WRITE_WATCHFACE, payload);
|
||||||
return;
|
return;
|
||||||
|
case DATA_CHUNK_REQUEST_FIRMWARE:
|
||||||
|
if (fwHelper == null || !fwHelper.isFirmware()) {
|
||||||
|
LOG.warn("We are not sending firmware - refusing request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handleChunkRequest(CmfCommand.DATA_CHUNK_WRITE_FIRMWARE, payload);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.warn("Got unknown data command {}", cmd);
|
LOG.warn("Got unknown data command {}", cmd);
|
||||||
@@ -123,6 +158,18 @@ public class CmfDataUploader implements CmfCharacteristic.Handler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: This is disabled until we figure out how to send the firmware version
|
||||||
|
if (fwHelper.isFirmware()) {
|
||||||
|
mSupport.sendCommand(
|
||||||
|
"transfer firmware init request",
|
||||||
|
CmfCommand.DATA_TRANSFER_FIRMWARE_INIT_1_REQUEST,
|
||||||
|
(byte) 0xa5
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
LOG.warn("Unsupported fwHelper for {}", fwHelper.getUri());
|
LOG.warn("Unsupported fwHelper for {}", fwHelper.getUri());
|
||||||
fwHelper = null;
|
fwHelper = null;
|
||||||
}
|
}
|
||||||
@@ -137,11 +184,19 @@ public class CmfDataUploader implements CmfCharacteristic.Handler {
|
|||||||
|
|
||||||
final TransactionBuilder builder = mSupport.createTransactionBuilder("send chunk offset " + offset);
|
final TransactionBuilder builder = mSupport.createTransactionBuilder("send chunk offset " + offset);
|
||||||
updateProgress(builder, progress, true);
|
updateProgress(builder, progress, true);
|
||||||
mSupport.sendData(
|
if (commandReply == CmfCommand.DATA_CHUNK_WRITE_FIRMWARE) {
|
||||||
"transfer watchface init request",
|
mSupport.sendFirmware(
|
||||||
commandReply,
|
"send firmware chunk",
|
||||||
ArrayUtils.subarray(fwHelper.getBytes(), offset, offset + length)
|
commandReply,
|
||||||
);
|
ArrayUtils.subarray(fwHelper.getBytes(), offset, offset + length)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
mSupport.sendData(
|
||||||
|
"send data chunk",
|
||||||
|
commandReply,
|
||||||
|
ArrayUtils.subarray(fwHelper.getBytes(), offset, offset + length)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleAck1(final CmfCommand commandReply, final byte[] payload) {
|
private void handleAck1(final CmfCommand commandReply, final byte[] payload) {
|
||||||
|
|||||||
+52
@@ -94,6 +94,10 @@ public class CmfWatchProSupport extends AbstractBTLESingleDeviceSupport implemen
|
|||||||
public static final UUID UUID_CHARACTERISTIC_CMF_SHELL_WRITE = UUID.fromString("77d4ff01-2fe2-2334-0d35-9ccd078f529c");
|
public static final UUID UUID_CHARACTERISTIC_CMF_SHELL_WRITE = UUID.fromString("77d4ff01-2fe2-2334-0d35-9ccd078f529c");
|
||||||
public static final UUID UUID_CHARACTERISTIC_CMF_SHELL_READ = UUID.fromString("77d4ff02-2fe2-2334-0d35-9ccd078f529c");
|
public static final UUID UUID_CHARACTERISTIC_CMF_SHELL_READ = UUID.fromString("77d4ff02-2fe2-2334-0d35-9ccd078f529c");
|
||||||
|
|
||||||
|
public static final UUID UUID_SERVICE_CMF_FIRMWARE = UUID.fromString("02f00000-0000-0000-0000-00000000fe00");
|
||||||
|
public static final UUID UUID_CHARACTERISTIC_CMF_FIRMWARE_WRITE = UUID.fromString("02f00000-0000-0000-0000-00000000ff01");
|
||||||
|
public static final UUID UUID_CHARACTERISTIC_CMF_FIRMWARE_READ = UUID.fromString("02f00000-0000-0000-0000-00000000ff02");
|
||||||
|
|
||||||
// An a5 byte is used a lot in single payloads, probably as a "proof of encryption"?
|
// An a5 byte is used a lot in single payloads, probably as a "proof of encryption"?
|
||||||
public static final byte A5 = (byte) 0xa5;
|
public static final byte A5 = (byte) 0xa5;
|
||||||
|
|
||||||
@@ -101,6 +105,10 @@ public class CmfWatchProSupport extends AbstractBTLESingleDeviceSupport implemen
|
|||||||
private CmfCharacteristic characteristicCommandWrite;
|
private CmfCharacteristic characteristicCommandWrite;
|
||||||
private CmfCharacteristic characteristicDataRead;
|
private CmfCharacteristic characteristicDataRead;
|
||||||
private CmfCharacteristic characteristicDataWrite;
|
private CmfCharacteristic characteristicDataWrite;
|
||||||
|
@Nullable
|
||||||
|
private CmfCharacteristic characteristicFirmwareRead;
|
||||||
|
@Nullable
|
||||||
|
private CmfCharacteristic characteristicFirmwareWrite;
|
||||||
|
|
||||||
private final byte[] authRandom1 = new byte[16];
|
private final byte[] authRandom1 = new byte[16];
|
||||||
private final byte[] authAppSecret = new byte[16];
|
private final byte[] authAppSecret = new byte[16];
|
||||||
@@ -116,12 +124,14 @@ public class CmfWatchProSupport extends AbstractBTLESingleDeviceSupport implemen
|
|||||||
addSupportedService(UUID_SERVICE_CMF_CMD);
|
addSupportedService(UUID_SERVICE_CMF_CMD);
|
||||||
addSupportedService(UUID_SERVICE_CMF_DATA);
|
addSupportedService(UUID_SERVICE_CMF_DATA);
|
||||||
addSupportedService(UUID_SERVICE_CMF_SHELL);
|
addSupportedService(UUID_SERVICE_CMF_SHELL);
|
||||||
|
addSupportedService(UUID_SERVICE_CMF_FIRMWARE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean useAutoConnect() {
|
public boolean useAutoConnect() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TransactionBuilder initializeDevice(final TransactionBuilder builder) {
|
protected TransactionBuilder initializeDevice(final TransactionBuilder builder) {
|
||||||
builder.setUpdateState(getDevice(), GBDevice.State.INITIALIZING, getContext());
|
builder.setUpdateState(getDevice(), GBDevice.State.INITIALIZING, getContext());
|
||||||
@@ -164,18 +174,35 @@ public class CmfWatchProSupport extends AbstractBTLESingleDeviceSupport implemen
|
|||||||
LOG.warn("Characteristic shell read is null");
|
LOG.warn("Characteristic shell read is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final BluetoothGattCharacteristic btCharacteristicFirmwareWrite = getCharacteristic(UUID_CHARACTERISTIC_CMF_FIRMWARE_WRITE);
|
||||||
|
if (btCharacteristicFirmwareWrite == null) {
|
||||||
|
LOG.warn("Characteristic firmware write is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
final BluetoothGattCharacteristic btCharacteristicFirmwareRead = getCharacteristic(UUID_CHARACTERISTIC_CMF_FIRMWARE_READ);
|
||||||
|
if (btCharacteristicFirmwareRead == null) {
|
||||||
|
LOG.warn("Characteristic firmware read is null");
|
||||||
|
}
|
||||||
|
|
||||||
dataUploader = new CmfDataUploader(this);
|
dataUploader = new CmfDataUploader(this);
|
||||||
|
|
||||||
characteristicCommandRead = new CmfCharacteristic(btCharacteristicCommandRead, this);
|
characteristicCommandRead = new CmfCharacteristic(btCharacteristicCommandRead, this);
|
||||||
characteristicCommandWrite = new CmfCharacteristic(btCharacteristicCommandWrite, null);
|
characteristicCommandWrite = new CmfCharacteristic(btCharacteristicCommandWrite, null);
|
||||||
characteristicDataRead = new CmfCharacteristic(btCharacteristicDataRead, dataUploader);
|
characteristicDataRead = new CmfCharacteristic(btCharacteristicDataRead, dataUploader);
|
||||||
characteristicDataWrite = new CmfCharacteristic(btCharacteristicDataWrite, null);
|
characteristicDataWrite = new CmfCharacteristic(btCharacteristicDataWrite, null);
|
||||||
|
if (btCharacteristicFirmwareRead != null && btCharacteristicFirmwareWrite != null) {
|
||||||
|
characteristicFirmwareRead = new CmfCharacteristic(btCharacteristicFirmwareRead, dataUploader);
|
||||||
|
characteristicFirmwareWrite = new CmfCharacteristic(btCharacteristicFirmwareWrite, null);
|
||||||
|
}
|
||||||
|
|
||||||
builder.notify(btCharacteristicCommandRead, true);
|
builder.notify(btCharacteristicCommandRead, true);
|
||||||
builder.notify(btCharacteristicDataRead, true);
|
builder.notify(btCharacteristicDataRead, true);
|
||||||
if (btCharacteristicShellRead != null) {
|
if (btCharacteristicShellRead != null) {
|
||||||
builder.notify(btCharacteristicShellRead, true);
|
builder.notify(btCharacteristicShellRead, true);
|
||||||
}
|
}
|
||||||
|
if (btCharacteristicFirmwareRead != null) {
|
||||||
|
builder.notify(btCharacteristicFirmwareRead, true);
|
||||||
|
}
|
||||||
|
|
||||||
builder.setUpdateState(getDevice(), GBDevice.State.AUTHENTICATING, getContext());
|
builder.setUpdateState(getDevice(), GBDevice.State.AUTHENTICATING, getContext());
|
||||||
|
|
||||||
@@ -186,6 +213,12 @@ public class CmfWatchProSupport extends AbstractBTLESingleDeviceSupport implemen
|
|||||||
characteristicCommandWrite.setSessionKey(secretKey);
|
characteristicCommandWrite.setSessionKey(secretKey);
|
||||||
characteristicDataRead.setSessionKey(secretKey);
|
characteristicDataRead.setSessionKey(secretKey);
|
||||||
characteristicDataWrite.setSessionKey(secretKey);
|
characteristicDataWrite.setSessionKey(secretKey);
|
||||||
|
if (characteristicFirmwareRead != null) {
|
||||||
|
characteristicFirmwareRead.setSessionKey(secretKey);
|
||||||
|
}
|
||||||
|
if (characteristicFirmwareWrite != null) {
|
||||||
|
characteristicFirmwareWrite.setSessionKey(secretKey);
|
||||||
|
}
|
||||||
|
|
||||||
sendCommand(builder, CmfCommand.AUTH_PHONE_NAME, ArrayUtils.addAll(new byte[]{A5}, Build.MODEL.getBytes(StandardCharsets.UTF_8)));
|
sendCommand(builder, CmfCommand.AUTH_PHONE_NAME, ArrayUtils.addAll(new byte[]{A5}, Build.MODEL.getBytes(StandardCharsets.UTF_8)));
|
||||||
} else if (btCharacteristicShellWrite != null) {
|
} else if (btCharacteristicShellWrite != null) {
|
||||||
@@ -221,6 +254,9 @@ public class CmfWatchProSupport extends AbstractBTLESingleDeviceSupport implemen
|
|||||||
} else if (characteristicUUID.equals(characteristicDataRead.getCharacteristicUUID())) {
|
} else if (characteristicUUID.equals(characteristicDataRead.getCharacteristicUUID())) {
|
||||||
characteristicDataRead.onCharacteristicChanged(value);
|
characteristicDataRead.onCharacteristicChanged(value);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (characteristicFirmwareRead != null && characteristicUUID.equals(characteristicFirmwareRead.getCharacteristicUUID())) {
|
||||||
|
characteristicFirmwareRead.onCharacteristicChanged(value);
|
||||||
|
return true;
|
||||||
} else if (characteristicUUID.equals(UUID_CHARACTERISTIC_CMF_SHELL_READ)) {
|
} else if (characteristicUUID.equals(UUID_CHARACTERISTIC_CMF_SHELL_READ)) {
|
||||||
handleShellCommand(value);
|
handleShellCommand(value);
|
||||||
return true;
|
return true;
|
||||||
@@ -255,6 +291,10 @@ public class CmfWatchProSupport extends AbstractBTLESingleDeviceSupport implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
case DATA_TRANSFER_FIRMWARE_INIT_1_REPLY:
|
||||||
|
// This one comes in the command characteristic because of reasons
|
||||||
|
dataUploader.onCommand(cmd, payload);
|
||||||
|
return;
|
||||||
case AUTH_PAIR_REPLY:
|
case AUTH_PAIR_REPLY:
|
||||||
final byte[] authRandom2 = ArrayUtils.subarray(payload, 0, 16);
|
final byte[] authRandom2 = ArrayUtils.subarray(payload, 0, 16);
|
||||||
final byte[] signedAuthRandom2 = ArrayUtils.subarray(payload, 16, 48);
|
final byte[] signedAuthRandom2 = ArrayUtils.subarray(payload, 16, 48);
|
||||||
@@ -326,6 +366,12 @@ public class CmfWatchProSupport extends AbstractBTLESingleDeviceSupport implemen
|
|||||||
characteristicCommandWrite.setSessionKey(sessionKey);
|
characteristicCommandWrite.setSessionKey(sessionKey);
|
||||||
characteristicDataRead.setSessionKey(sessionKey);
|
characteristicDataRead.setSessionKey(sessionKey);
|
||||||
characteristicDataWrite.setSessionKey(sessionKey);
|
characteristicDataWrite.setSessionKey(sessionKey);
|
||||||
|
if (characteristicFirmwareRead != null) {
|
||||||
|
characteristicFirmwareRead.setSessionKey(sessionKey);
|
||||||
|
}
|
||||||
|
if (characteristicFirmwareWrite != null) {
|
||||||
|
characteristicFirmwareWrite.setSessionKey(sessionKey);
|
||||||
|
}
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
LOG.error("Failed to compute session key from auth nonce", e);
|
LOG.error("Failed to compute session key from auth nonce", e);
|
||||||
return;
|
return;
|
||||||
@@ -452,6 +498,12 @@ public class CmfWatchProSupport extends AbstractBTLESingleDeviceSupport implemen
|
|||||||
builder.queue(getQueue());
|
builder.queue(getQueue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendFirmware(final String taskName, final CmfCommand cmd, final byte... payload) {
|
||||||
|
final TransactionBuilder builder = createTransactionBuilder(taskName);
|
||||||
|
characteristicFirmwareWrite.sendCommand(builder, cmd, payload);
|
||||||
|
builder.queue(getQueue());
|
||||||
|
}
|
||||||
|
|
||||||
private void handleShellCommand(final byte[] bytes) {
|
private void handleShellCommand(final byte[] bytes) {
|
||||||
final String shellCommand = new String(bytes).strip();
|
final String shellCommand = new String(bytes).strip();
|
||||||
if (!shellCommand.startsWith("GETSECRET:")) {
|
if (!shellCommand.startsWith("GETSECRET:")) {
|
||||||
|
|||||||
Reference in New Issue
Block a user