1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-14 14:09:28 +01:00

Fix pairing with MI1A

This commit is contained in:
Sergey Trofimov 2015-10-18 21:54:22 +03:00
parent 7591d4a8af
commit d57c6166b9
3 changed files with 115 additions and 57 deletions

View File

@ -1,7 +1,10 @@
package nodomain.freeyourgadget.gadgetbridge.devices.miband; package nodomain.freeyourgadget.gadgetbridge.devices.miband;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.DeviceInfo;
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums; import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
import java.util.Arrays;
/** /**
* Created by UgoRaffaele on 30/01/2015. * Created by UgoRaffaele on 30/01/2015.
*/ */
@ -56,46 +59,6 @@ public class UserInfo {
this.height = height; this.height = height;
this.weight = weight; this.weight = weight;
this.type = type; this.type = type;
byte[] sequence = new byte[20];
int uid = calculateUidFrom(alias);
String normalizedAlias = ensureTenCharacters(alias);
sequence[0] = (byte) uid;
sequence[1] = (byte) (uid >>> 8);
sequence[2] = (byte) (uid >>> 16);
sequence[3] = (byte) (uid >>> 24);
sequence[4] = (byte) (gender & 0xff);
sequence[5] = (byte) (age & 0xff);
sequence[6] = (byte) (height & 0xff);
sequence[7] = (byte) (weight & 0xff);
sequence[8] = (byte) (type & 0xff);
for (int u = 9; u < 19; u++)
sequence[u] = normalizedAlias.getBytes()[u - 9];
byte[] crcSequence = new byte[19];
System.arraycopy(sequence, 0, crcSequence, 0, crcSequence.length);
sequence[19] = (byte) ((CheckSums.getCRC8(crcSequence) ^ Integer.parseInt(address.substring(address.length() - 2), 16)) & 0xff);
this.data = sequence;
}
private String ensureTenCharacters(String alias) {
char[] result = new char[10];
int aliasLen = alias.length();
int maxLen = Math.min(10, alias.length());
int diff = 10 - maxLen;
for (int i = 0; i < maxLen; i++) {
result[i + diff] = alias.charAt(i);
}
for (int i = 0; i < diff; i++) {
result[i] = '0';
}
return new String(result);
} }
private int calculateUidFrom(String alias) { private int calculateUidFrom(String alias) {
@ -108,7 +71,34 @@ public class UserInfo {
return uid; return uid;
} }
public byte[] getData() { public byte[] getData(DeviceInfo mDeviceInfo) {
return this.data; byte[] sequence = new byte[20];
int uid = calculateUidFrom(alias);
sequence[0] = (byte) uid;
sequence[1] = (byte) (uid >>> 8);
sequence[2] = (byte) (uid >>> 16);
sequence[3] = (byte) (uid >>> 24);
sequence[4] = (byte) (gender & 0xff);
sequence[5] = (byte) (age & 0xff);
sequence[6] = (byte) (height & 0xff);
sequence[7] = (byte) (weight & 0xff);
sequence[8] = (byte) (type & 0xff);
int aliasFrom = 9;
if (mDeviceInfo.isMili1A()) {
sequence[9] = (byte) (mDeviceInfo.feature & 255);
sequence[10] = (byte) (mDeviceInfo.appearance & 255);
aliasFrom = 11;
}
byte[] aliasBytes = alias.substring(0, Math.min(alias.length(), 19-aliasFrom)).getBytes();
System.arraycopy(aliasBytes, 0, sequence, aliasFrom, aliasBytes.length);
byte[] crcSequence = Arrays.copyOf(sequence, 19);
sequence[19] = (byte) ((CheckSums.getCRC8(crcSequence) ^ Integer.parseInt(this.btAddress.substring(this.btAddress.length() - 2), 16)) & 0xff);
return sequence;
} }
} }

View File

@ -1,29 +1,84 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband; package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
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.util.CheckSums;
import java.util.Locale;
public class DeviceInfo extends AbstractInfo { public class DeviceInfo extends AbstractInfo {
public final String deviceId;
public final int profileVersion;
public final int fwVersion;
public final int hwVersion;
public final int feature;
public final int appearance;
private boolean isChecksumCorrect(byte[] data) {
int crc8 = CheckSums.getCRC8(new byte[]{data[0], data[1], data[2], data[3], data[4], data[5], data[6]});
return data[7] == (crc8 ^ data[3] & 255);
}
public DeviceInfo(byte[] data) { public DeviceInfo(byte[] data) {
super(data); super(data);
if ((data.length == 16 || data.length == 20) && isChecksumCorrect(data)) {
deviceId = String.format("%02X%02X%02X%02X%02X%02X%02X%02X", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
profileVersion = getInt(data, 8);
fwVersion = getInt(data, 12);
hwVersion = Integer.decode("0x" + deviceId.substring(12, 14)).intValue();
feature = Integer.decode("0x" + deviceId.substring(8, 10)).intValue();
appearance = Integer.decode("0x" + deviceId.substring(10, 12)).intValue();
} else {
deviceId = "crc error";
profileVersion = -1;
fwVersion = -1;
hwVersion = -1;
feature = -1;
appearance = -1;
}
}
public static int getInt(byte[] data, int from, int len) {
int ret = 0;
for(int i = 0; i < len; ++i) {
ret |= (data[from + i] & 255) << i * 8;
}
return ret;
}
private int getInt(byte[] data, int from) {
return getInt(data, from, 4);
} }
public String getHumanFirmwareVersion() { public String getHumanFirmwareVersion() {
if (mData.length == 16) { if (fwVersion == -1)
int last = 15; return GBApplication.getContext().getString(R.string._unknown_);
return String.format(Locale.US, "%d.%d.%d.%d", mData[last], mData[last - 1], mData[last - 2], mData[last - 3]);
} return String.format(Locale.US, "%d.%d.%d.%d",
return GBApplication.getContext().getString(R.string._unknown_); fwVersion >> 24 & 255,
fwVersion >> 16 & 255,
fwVersion >> 8 & 255,
fwVersion & 255);
} }
public int getFirmwareVersion() { public int getFirmwareVersion() {
if (mData.length == 16) { return fwVersion;
int last = 15; }
return (mData[last] << 24) | (mData[last - 1] << 16) | (mData[last - 2] << 8) | mData[last - 3];
} @Override
return -1; public String toString() {
return "DeviceInfo{" +
"deviceId='" + deviceId + '\'' +
", profileVersion=" + profileVersion +
", fwVersion=" + fwVersion +
", hwVersion=" + hwVersion +
'}';
}
public boolean isMili1A() {
return (this.feature & 255) == 5 && (this.appearance & 255) == 0 || (this.feature & 255) == 0 && (this.hwVersion & 255) == 208;
} }
} }

View File

@ -9,6 +9,7 @@ import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.widget.Toast; import android.widget.Toast;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WriteAction;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -91,13 +92,13 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
protected TransactionBuilder initializeDevice(TransactionBuilder builder) { protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
builder.add(new SetDeviceStateAction(getDevice(), State.INITIALIZING, getContext())); builder.add(new SetDeviceStateAction(getDevice(), State.INITIALIZING, getContext()));
pair(builder) pair(builder)
.requestDeviceInfo(builder)
.sendUserInfo(builder) .sendUserInfo(builder)
.setWearLocation(builder) .setWearLocation(builder)
.setFitnessGoal(builder) .setFitnessGoal(builder)
.enableNotifications(builder, true) .enableNotifications(builder, true)
.setCurrentTime(builder) .setCurrentTime(builder)
.requestBatteryInfo(builder) .requestBatteryInfo(builder)
.requestDeviceInfo(builder)
.setInitialized(builder); .setInitialized(builder);
return builder; return builder;
@ -268,8 +269,19 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
*/ */
private MiBandSupport sendUserInfo(TransactionBuilder builder) { private MiBandSupport sendUserInfo(TransactionBuilder builder) {
LOG.debug("Writing User Info!"); LOG.debug("Writing User Info!");
BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_USER_INFO); builder.add(new BtLEAction(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_USER_INFO)) {
builder.write(characteristic, MiBandCoordinator.getAnyUserInfo(getDevice().getAddress()).getData()); @Override
public boolean expectsResult() {
return true;
}
@Override
public boolean run(BluetoothGatt gatt) {
return new WriteAction(getCharacteristic(),
MiBandCoordinator.getAnyUserInfo(getDevice().getAddress()).getData(mDeviceInfo)
).run(gatt);
}
});
return this; return this;
} }
@ -749,6 +761,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
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);
LOG.warn(mDeviceInfo.toString());
versionCmd.fwVersion = mDeviceInfo.getHumanFirmwareVersion(); versionCmd.fwVersion = mDeviceInfo.getHumanFirmwareVersion();
handleGBDeviceEvent(versionCmd); handleGBDeviceEvent(versionCmd);
} }