mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-27 11:05:49 +01:00
commit
e0289f63ce
@ -1,7 +1,10 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.miband;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.DeviceInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by UgoRaffaele on 30/01/2015.
|
||||
*/
|
||||
@ -56,46 +59,6 @@ public class UserInfo {
|
||||
this.height = height;
|
||||
this.weight = weight;
|
||||
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) {
|
||||
@ -108,7 +71,34 @@ public class UserInfo {
|
||||
return uid;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return this.data;
|
||||
public byte[] getData(DeviceInfo mDeviceInfo) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -368,7 +368,7 @@ public final class BtLEQueue {
|
||||
try {
|
||||
getCallbackToUse().onCharacteristicRead(gatt, characteristic, status);
|
||||
} catch (Throwable ex) {
|
||||
LOG.error("onCharaceristicRead: " + ex.getMessage(), ex);
|
||||
LOG.error("onCharacteristicRead: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
checkWaitingCharacteristic(characteristic, status);
|
||||
|
@ -1,29 +1,84 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
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) {
|
||||
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() {
|
||||
if (mData.length == 16) {
|
||||
int last = 15;
|
||||
return String.format(Locale.US, "%d.%d.%d.%d", mData[last], mData[last - 1], mData[last - 2], mData[last - 3]);
|
||||
}
|
||||
return GBApplication.getContext().getString(R.string._unknown_);
|
||||
if (fwVersion == -1)
|
||||
return GBApplication.getContext().getString(R.string._unknown_);
|
||||
|
||||
return String.format(Locale.US, "%d.%d.%d.%d",
|
||||
fwVersion >> 24 & 255,
|
||||
fwVersion >> 16 & 255,
|
||||
fwVersion >> 8 & 255,
|
||||
fwVersion & 255);
|
||||
}
|
||||
|
||||
public int getFirmwareVersion() {
|
||||
if (mData.length == 16) {
|
||||
int last = 15;
|
||||
return (mData[last] << 24) | (mData[last - 1] << 16) | (mData[last - 2] << 8) | mData[last - 3];
|
||||
}
|
||||
return -1;
|
||||
return fwVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import android.preference.PreferenceManager;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WriteAction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -91,13 +92,13 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
||||
builder.add(new SetDeviceStateAction(getDevice(), State.INITIALIZING, getContext()));
|
||||
pair(builder)
|
||||
.requestDeviceInfo(builder)
|
||||
.sendUserInfo(builder)
|
||||
.setWearLocation(builder)
|
||||
.setFitnessGoal(builder)
|
||||
.enableNotifications(builder, true)
|
||||
.setCurrentTime(builder)
|
||||
.requestBatteryInfo(builder)
|
||||
.requestDeviceInfo(builder)
|
||||
.setInitialized(builder);
|
||||
|
||||
return builder;
|
||||
@ -268,8 +269,19 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
*/
|
||||
private MiBandSupport sendUserInfo(TransactionBuilder builder) {
|
||||
LOG.debug("Writing User Info!");
|
||||
BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_USER_INFO);
|
||||
builder.write(characteristic, MiBandCoordinator.getAnyUserInfo(getDevice().getAddress()).getData());
|
||||
builder.add(new BtLEAction(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_USER_INFO)) {
|
||||
@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;
|
||||
}
|
||||
|
||||
@ -749,6 +761,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
private void handleDeviceInfo(byte[] value, int status) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
mDeviceInfo = new DeviceInfo(value);
|
||||
LOG.warn(mDeviceInfo.toString());
|
||||
versionCmd.fwVersion = mDeviceInfo.getHumanFirmwareVersion();
|
||||
handleGBDeviceEvent(versionCmd);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user