1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-07-24 07:38:45 +02:00

Mi Band: Support activity fetching in later firmwares (needs testing)

Based on the profile version which is 0x2000700 for both the bug reporter on a Mi Band 1 and for me on a Mi Band 1s
this either expects packets with length 20 (old firmwares) or 16 for HR enabled bands and 18 for non-HR enabled bands (new firmwares)

We check for profile version >=0x02000000 which is guessed, that needs confirmation for older firmwares and untested ones

Fixes #915
This commit is contained in:
Andreas Shimokawa 2017-12-28 01:07:25 +01:00
parent f85fd2dc46
commit dc51714d01
3 changed files with 30 additions and 16 deletions

View File

@ -95,6 +95,10 @@ public class DeviceInfo extends AbstractInfo {
return fw2Version;
}
public int getProfileVersion() {
return profileVersion;
}
public void setTest1AHRMode(boolean enableTestMode) {
test1AHRMode = enableTestMode;
}

View File

@ -67,11 +67,11 @@ public class FetchActivityOperation extends AbstractMiBand1Operation {
private final int activityMetadataLength = 11;
//temporary buffer, size is a multiple of 60 because we want to store complete minutes (1 minute = 3 or 4 bytes)
private final int activityDataHolderSize;
private final boolean hasExtendedActivityData;
private final boolean hasPacketCounter;
private static class ActivityStruct {
private class ActivityStruct {
private int maxDataPacketLength = 20;
private int lastNotifiedProgress;
private final byte[] activityDataHolder;
private final int activityDataHolderSize;
@ -86,21 +86,22 @@ public class FetchActivityOperation extends AbstractMiBand1Operation {
//same as above, but remains untouched for the ack message
private GregorianCalendar activityDataTimestampToAck = null;
ActivityStruct(int activityDataHolderSize) {
ActivityStruct(int activityDataHolderSize, int maxDataPacketLength) {
this.activityDataHolderSize = activityDataHolderSize;
this.maxDataPacketLength = maxDataPacketLength;
activityDataHolder = new byte[activityDataHolderSize];
}
public boolean hasRoomFor(byte[] value) {
boolean hasRoomFor(byte[] value) {
return activityDataRemainingBytes >= value.length;
}
public boolean isValidData(byte[] value) {
boolean isValidData(byte[] value) {
//I don't like this clause, but until we figure out why we get different data sometimes this should work
return value.length == 20 || value.length == activityDataRemainingBytes;
return value.length == maxDataPacketLength || value.length == activityDataRemainingBytes;
}
public boolean isBufferFull() {
boolean isBufferFull() {
return activityDataHolderSize == activityDataHolderProgress;
}
@ -116,11 +117,11 @@ public class FetchActivityOperation extends AbstractMiBand1Operation {
GB.assertThat(activityDataRemainingBytes >= 0, "Illegal state, remaining bytes is negative");
}
public boolean isFirstChunk() {
boolean isFirstChunk() {
return activityDataTimestampProgress == null;
}
public void startNewBlock(GregorianCalendar timestamp, int dataUntilNextHeader) {
void startNewBlock(GregorianCalendar timestamp, int dataUntilNextHeader) {
GB.assertThat(timestamp != null, "Timestamp must not be null");
if (isFirstChunk()) {
@ -140,11 +141,11 @@ public class FetchActivityOperation extends AbstractMiBand1Operation {
validate();
}
public boolean isBlockFinished() {
boolean isBlockFinished() {
return activityDataRemainingBytes == 0;
}
public void bufferFlushed(int minutes) {
void bufferFlushed(int minutes) {
activityDataTimestampProgress.add(Calendar.MINUTE, minutes);
activityDataHolderProgress = 0;
lastNotifiedProgress = 0;
@ -156,8 +157,11 @@ public class FetchActivityOperation extends AbstractMiBand1Operation {
public FetchActivityOperation(MiBandSupport support) {
super(support);
hasExtendedActivityData = support.getDeviceInfo().supportsHeartrate();
activityDataHolderSize = getBytesPerMinuteOfActivityData() * 60 * 4; // 4h
activityStruct = new ActivityStruct(activityDataHolderSize);
hasPacketCounter = support.getDeviceInfo().getProfileVersion() >= 0x02000000;
//temporary buffer, size is a multiple of 60 because we want to store complete minutes (1 minute = 3 or 4 bytes)
int activityDataHolderSize = getBytesPerMinuteOfActivityData() * 60 * 4;
int maxDataPacketLength = hasPacketCounter ? (hasExtendedActivityData ? 16 : 18) : 20;
activityStruct = new ActivityStruct(activityDataHolderSize, maxDataPacketLength);
}
@Override
@ -216,7 +220,13 @@ public class FetchActivityOperation extends AbstractMiBand1Operation {
if (value.length == activityMetadataLength) {
handleActivityMetadata(value);
} else {
bufferActivityData(value);
if (hasPacketCounter) {
byte[] valueChopped = new byte[value.length - 1];
System.arraycopy(value, 1, valueChopped, 0, value.length - 1);
bufferActivityData(valueChopped);
} else {
bufferActivityData(value);
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("activity data: length: " + value.length + ", remaining bytes: " + activityStruct.activityDataRemainingBytes);

View File

@ -298,7 +298,7 @@
<string name="user_feedback_miband_set_alarms_failed">Feil ved setting av alarm, prøv igjen.</string>
<string name="user_feedback_miband_set_alarms_ok">Alarmer sendt til enhet.</string>
<string name="chart_no_data_synchronize">Ingen data. Synkroniser enhet?</string>
<string name="user_feedback_miband_activity_data_transfer">I ferd med å overføre %1$d med data fra %2$s</string>
<string name="user_feedback_miband_activity_data_transfer">I ferd med å overføre %1$s med data fra %2$s</string>
<string name="miband_prefs_fitness_goal">Stegmål</string>
<string name="dbaccess_error_executing">Feil under kjøring av \"%1$s\"</string>
<string name="controlcenter_start_activitymonitor">Din aktivitet (alfa)</string>