mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-02-13 19:05:39 +01:00
Huawei: Parse more workout information. No UI.
This commit is contained in:
parent
02aa267e8f
commit
fdea3b7955
@ -54,7 +54,7 @@ public class GBDaoGenerator {
|
|||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
final Schema schema = new Schema(95, MAIN_PACKAGE + ".entities");
|
final Schema schema = new Schema(96, MAIN_PACKAGE + ".entities");
|
||||||
|
|
||||||
Entity userAttributes = addUserAttributes(schema);
|
Entity userAttributes = addUserAttributes(schema);
|
||||||
Entity user = addUserInfo(schema, userAttributes);
|
Entity user = addUserInfo(schema, userAttributes);
|
||||||
@ -161,6 +161,7 @@ public class GBDaoGenerator {
|
|||||||
addHuaweiWorkoutPaceSample(schema, huaweiWorkoutSummary);
|
addHuaweiWorkoutPaceSample(schema, huaweiWorkoutSummary);
|
||||||
addHuaweiWorkoutSwimSegmentsSample(schema, huaweiWorkoutSummary);
|
addHuaweiWorkoutSwimSegmentsSample(schema, huaweiWorkoutSummary);
|
||||||
addHuaweiWorkoutSpO2Sample(schema, huaweiWorkoutSummary);
|
addHuaweiWorkoutSpO2Sample(schema, huaweiWorkoutSummary);
|
||||||
|
addHuaweiWorkoutSectionsSample(schema, huaweiWorkoutSummary);
|
||||||
|
|
||||||
Entity huaweiDictData = addHuaweiDictData(schema, user, device);
|
Entity huaweiDictData = addHuaweiDictData(schema, user, device);
|
||||||
addHuaweiDictDataValues(schema, huaweiDictData);
|
addHuaweiDictDataValues(schema, huaweiDictData);
|
||||||
@ -1502,6 +1503,18 @@ public class GBDaoGenerator {
|
|||||||
workoutDataSample.addShortProperty("frequency").notNull();
|
workoutDataSample.addShortProperty("frequency").notNull();
|
||||||
workoutDataSample.addIntProperty("altitude");
|
workoutDataSample.addIntProperty("altitude");
|
||||||
|
|
||||||
|
workoutDataSample.addShortProperty("hangTime").notNull();
|
||||||
|
workoutDataSample.addShortProperty("impactHangRate").notNull();
|
||||||
|
workoutDataSample.addByteProperty("rideCadence").notNull();
|
||||||
|
workoutDataSample.addFloatProperty("ap").notNull();
|
||||||
|
workoutDataSample.addFloatProperty("vo").notNull();
|
||||||
|
workoutDataSample.addFloatProperty("gtb").notNull();
|
||||||
|
workoutDataSample.addFloatProperty("vr").notNull();
|
||||||
|
workoutDataSample.addByteProperty("ceiling").notNull();
|
||||||
|
workoutDataSample.addByteProperty("temp").notNull();
|
||||||
|
workoutDataSample.addByteProperty("spo2").notNull();
|
||||||
|
workoutDataSample.addShortProperty("cns").notNull();
|
||||||
|
|
||||||
return workoutDataSample;
|
return workoutDataSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1559,6 +1572,39 @@ public class GBDaoGenerator {
|
|||||||
return workoutSwimSegmentsSample;
|
return workoutSwimSegmentsSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Entity addHuaweiWorkoutSectionsSample(Schema schema, Entity summaryEntity) {
|
||||||
|
Entity workoutSectionsSample = addEntity(schema, "HuaweiWorkoutSectionsSample");
|
||||||
|
|
||||||
|
workoutSectionsSample.setJavaDoc("Contains Huawei Workout Section data samples");
|
||||||
|
|
||||||
|
Property id = workoutSectionsSample.addLongProperty("workoutId").primaryKey().notNull().getProperty();
|
||||||
|
workoutSectionsSample.addToOne(summaryEntity, id);
|
||||||
|
|
||||||
|
workoutSectionsSample.addIntProperty("dataIdx").notNull().primaryKey();
|
||||||
|
workoutSectionsSample.addIntProperty("rowIdx").notNull().primaryKey();
|
||||||
|
|
||||||
|
workoutSectionsSample.addIntProperty("num").notNull();
|
||||||
|
workoutSectionsSample.addLongProperty("time").notNull();
|
||||||
|
workoutSectionsSample.addLongProperty("distance").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("pace").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("heartRate").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("cadence").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("stepLength").notNull();
|
||||||
|
workoutSectionsSample.addLongProperty("totalRise").notNull();
|
||||||
|
workoutSectionsSample.addLongProperty("totalDescend").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("groundContactTime").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("groundImpact").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("swingAngle").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("eversion").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("avgCadence").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("intervalTrainingType").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("divingMaxDepth").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("divingUnderwaterTime").notNull();
|
||||||
|
workoutSectionsSample.addIntProperty("divingBreakTime").notNull();
|
||||||
|
|
||||||
|
return workoutSectionsSample;
|
||||||
|
}
|
||||||
|
|
||||||
private static Entity addHuaweiDictData(Schema schema, Entity user, Entity device) {
|
private static Entity addHuaweiDictData(Schema schema, Entity user, Entity device) {
|
||||||
Entity dictData = addEntity(schema, "HuaweiDictData");
|
Entity dictData = addEntity(schema, "HuaweiDictData");
|
||||||
|
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.database.schema;
|
||||||
|
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSampleDao;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao;
|
||||||
|
|
||||||
|
public class GadgetbridgeUpdate_96 implements DBUpdateScript {
|
||||||
|
@Override
|
||||||
|
public void upgradeSchema(final SQLiteDatabase db) {
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.HangTime.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.HangTime.columnName + "\" INTEGER NOT NULL DEFAULT -1;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.ImpactHangRate.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.ImpactHangRate.columnName + "\" INTEGER NOT NULL DEFAULT -1;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.RideCadence.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.RideCadence.columnName + "\" INTEGER NOT NULL DEFAULT -1;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Ap.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.Ap.columnName + "\" FLOAT NOT NULL DEFAULT 0;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Vo.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.Vo.columnName + "\" FLOAT NOT NULL DEFAULT 0;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Gtb.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.Gtb.columnName + "\" FLOAT NOT NULL DEFAULT 0;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Vr.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.Vr.columnName + "\" FLOAT NOT NULL DEFAULT 0;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Ceiling.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.Ceiling.columnName + "\" INTEGER NOT NULL DEFAULT -1;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Temp.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.Temp.columnName + "\" INTEGER NOT NULL DEFAULT -1;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Spo2.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.Spo2.columnName + "\" INTEGER NOT NULL DEFAULT -1;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Cns.columnName, db)) {
|
||||||
|
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
|
||||||
|
+ HuaweiWorkoutDataSampleDao.Properties.Cns.columnName + "\" INTEGER NOT NULL DEFAULT -1;";
|
||||||
|
db.execSQL(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void downgradeSchema(final SQLiteDatabase db) {
|
||||||
|
}
|
||||||
|
}
|
@ -75,6 +75,8 @@ public class HuaweiCoordinator {
|
|||||||
private boolean supportsTruSleepNewSync = false;
|
private boolean supportsTruSleepNewSync = false;
|
||||||
private boolean supportsGpsNewSync = false;
|
private boolean supportsGpsNewSync = false;
|
||||||
|
|
||||||
|
private boolean supportsWorkoutNewSteps = false;
|
||||||
|
|
||||||
private Watchface.WatchfaceDeviceParams watchfaceDeviceParams;
|
private Watchface.WatchfaceDeviceParams watchfaceDeviceParams;
|
||||||
|
|
||||||
private App.AppDeviceParams appDeviceParams;
|
private App.AppDeviceParams appDeviceParams;
|
||||||
@ -585,6 +587,10 @@ public class HuaweiCoordinator {
|
|||||||
return supportsCommandForService(0x17, 0x01);
|
return supportsCommandForService(0x17, 0x01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean supportsWorkoutCapability() {
|
||||||
|
return supportsCommandForService(0x17, 0x15);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean supportsWorkoutsTrustHeartRate() {
|
public boolean supportsWorkoutsTrustHeartRate() {
|
||||||
return supportsCommandForService(0x17, 0x17);
|
return supportsCommandForService(0x17, 0x17);
|
||||||
}
|
}
|
||||||
@ -966,6 +972,14 @@ public class HuaweiCoordinator {
|
|||||||
this.supportsGpsNewSync = supportsGpsNewSync;
|
this.supportsGpsNewSync = supportsGpsNewSync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSupportsWorkoutNewSteps() {
|
||||||
|
return supportsWorkoutNewSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupportsWorkoutNewSteps(boolean supportsWorkoutNewSteps) {
|
||||||
|
this.supportsWorkoutNewSteps = supportsWorkoutNewSteps;
|
||||||
|
}
|
||||||
|
|
||||||
public String getOtaSoftwareVersion() {
|
public String getOtaSoftwareVersion() {
|
||||||
return otaSoftwareVersion;
|
return otaSoftwareVersion;
|
||||||
}
|
}
|
||||||
|
@ -582,6 +582,10 @@ public class HuaweiPacket {
|
|||||||
return new Workout.WorkoutSwimSegments.Response(paramsProvider).fromPacket(this);
|
return new Workout.WorkoutSwimSegments.Response(paramsProvider).fromPacket(this);
|
||||||
case Workout.WorkoutSpO2.id:
|
case Workout.WorkoutSpO2.id:
|
||||||
return new Workout.WorkoutSpO2.Response(paramsProvider).fromPacket(this);
|
return new Workout.WorkoutSpO2.Response(paramsProvider).fromPacket(this);
|
||||||
|
case Workout.WorkoutCapability.id:
|
||||||
|
return new Workout.WorkoutCapability.Response(paramsProvider).fromPacket(this);
|
||||||
|
case Workout.WorkoutSections.id:
|
||||||
|
return new Workout.WorkoutSections.Response(paramsProvider).fromPacket(this);
|
||||||
default:
|
default:
|
||||||
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
|
||||||
return this;
|
return this;
|
||||||
|
@ -28,6 +28,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
|
||||||
|
|
||||||
public class Workout {
|
public class Workout {
|
||||||
|
|
||||||
public static final byte id = 0x17;
|
public static final byte id = 0x17;
|
||||||
|
|
||||||
public static class WorkoutCount {
|
public static class WorkoutCount {
|
||||||
@ -63,6 +64,7 @@ public class Workout {
|
|||||||
public short paceCount;
|
public short paceCount;
|
||||||
public short segmentsCount = 0;
|
public short segmentsCount = 0;
|
||||||
public short spO2Count = 0;
|
public short spO2Count = 0;
|
||||||
|
public short sectionsCount = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,12 +92,15 @@ public class Workout {
|
|||||||
workoutNumber.workoutNumber = subContainerTlv.getShort(0x06);
|
workoutNumber.workoutNumber = subContainerTlv.getShort(0x06);
|
||||||
workoutNumber.dataCount = subContainerTlv.getShort(0x07);
|
workoutNumber.dataCount = subContainerTlv.getShort(0x07);
|
||||||
workoutNumber.paceCount = subContainerTlv.getShort(0x08);
|
workoutNumber.paceCount = subContainerTlv.getShort(0x08);
|
||||||
if(subContainerTlv.contains(0x09)) {
|
if (subContainerTlv.contains(0x09)) {
|
||||||
workoutNumber.segmentsCount = subContainerTlv.getShort(0x09);
|
workoutNumber.segmentsCount = subContainerTlv.getShort(0x09);
|
||||||
}
|
}
|
||||||
if(subContainerTlv.contains(0x0c)) {
|
if (subContainerTlv.contains(0x0c)) {
|
||||||
workoutNumber.spO2Count = subContainerTlv.getShort(0x0c);
|
workoutNumber.spO2Count = subContainerTlv.getShort(0x0c);
|
||||||
}
|
}
|
||||||
|
if (subContainerTlv.contains(0x0d)) {
|
||||||
|
workoutNumber.sectionsCount = subContainerTlv.getShort(0x0d);
|
||||||
|
}
|
||||||
this.workoutNumbers.add(workoutNumber);
|
this.workoutNumbers.add(workoutNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,17 +290,23 @@ public class Workout {
|
|||||||
public Request(
|
public Request(
|
||||||
ParamsProvider paramsProvider,
|
ParamsProvider paramsProvider,
|
||||||
short workoutNumber,
|
short workoutNumber,
|
||||||
short dataNumber
|
short dataNumber,
|
||||||
|
boolean newSteps
|
||||||
) {
|
) {
|
||||||
super(paramsProvider);
|
super(paramsProvider);
|
||||||
|
|
||||||
this.serviceId = Workout.id;
|
this.serviceId = Workout.id;
|
||||||
this.commandId = id;
|
this.commandId = id;
|
||||||
|
|
||||||
this.tlv = new HuaweiTLV().put(0x81, new HuaweiTLV()
|
HuaweiTLV data = new HuaweiTLV()
|
||||||
.put(0x02, workoutNumber)
|
.put(0x02, workoutNumber)
|
||||||
.put(0x03, dataNumber)
|
.put(0x03, dataNumber);
|
||||||
);
|
if (newSteps) {
|
||||||
|
data.put(0x06, (byte) 1);
|
||||||
|
}
|
||||||
|
data.put(0x07);
|
||||||
|
|
||||||
|
this.tlv = new HuaweiTLV().put(0x81, data);
|
||||||
|
|
||||||
this.complete = true;
|
this.complete = true;
|
||||||
}
|
}
|
||||||
@ -311,6 +322,7 @@ public class Workout {
|
|||||||
public byte dataLength;
|
public byte dataLength;
|
||||||
public short bitmap; // TODO: can this be enum-like?
|
public short bitmap; // TODO: can this be enum-like?
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Header{" +
|
return "Header{" +
|
||||||
@ -342,6 +354,17 @@ public class Workout {
|
|||||||
public byte midFootLanding = -1;
|
public byte midFootLanding = -1;
|
||||||
public byte backFootLanding = -1;
|
public byte backFootLanding = -1;
|
||||||
public byte eversionAngle = -1;
|
public byte eversionAngle = -1;
|
||||||
|
public short hangTime = -1;
|
||||||
|
public short impactHangRate = -1;
|
||||||
|
public byte rideCadence = -1;
|
||||||
|
public float ap = 0.0F;
|
||||||
|
public float vo = 0.0F;
|
||||||
|
public float gtb = 0.0F;
|
||||||
|
public float vr = 0.0F;
|
||||||
|
public byte ceiling = -1;
|
||||||
|
public byte temp = -1;
|
||||||
|
public byte spo2 = -1;
|
||||||
|
public short cns = -1;
|
||||||
|
|
||||||
public short swolf = -1;
|
public short swolf = -1;
|
||||||
public short strokeRate = -1;
|
public short strokeRate = -1;
|
||||||
@ -353,6 +376,7 @@ public class Workout {
|
|||||||
|
|
||||||
public int timestamp = -1; // Calculated timestamp for this data point
|
public int timestamp = -1; // Calculated timestamp for this data point
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Data{" +
|
return "Data{" +
|
||||||
@ -369,6 +393,17 @@ public class Workout {
|
|||||||
", midFootLanding=" + midFootLanding +
|
", midFootLanding=" + midFootLanding +
|
||||||
", backFootLanding=" + backFootLanding +
|
", backFootLanding=" + backFootLanding +
|
||||||
", eversionAngle=" + eversionAngle +
|
", eversionAngle=" + eversionAngle +
|
||||||
|
", hangTime=" + hangTime +
|
||||||
|
", impactHangRate=" + impactHangRate +
|
||||||
|
", rideCadence=" + rideCadence +
|
||||||
|
", ap=" + ap +
|
||||||
|
", vo=" + vo +
|
||||||
|
", gtb=" + gtb +
|
||||||
|
", vr=" + vr +
|
||||||
|
", ceiling=" + ceiling +
|
||||||
|
", temp=" + temp +
|
||||||
|
", spo2=" + spo2 +
|
||||||
|
", cns=" + cns +
|
||||||
", swolf=" + swolf +
|
", swolf=" + swolf +
|
||||||
", strokeRate=" + strokeRate +
|
", strokeRate=" + strokeRate +
|
||||||
", calories=" + calories +
|
", calories=" + calories +
|
||||||
@ -387,7 +422,8 @@ public class Workout {
|
|||||||
public short dataNumber;
|
public short dataNumber;
|
||||||
public byte[] rawHeader;
|
public byte[] rawHeader;
|
||||||
public byte[] rawData;
|
public byte[] rawData;
|
||||||
public short innerBitmap;
|
public int innerBitmap = 0;
|
||||||
|
public int extraDataLength = 0;
|
||||||
|
|
||||||
public Header header;
|
public Header header;
|
||||||
public List<Data> dataList;
|
public List<Data> dataList;
|
||||||
@ -416,11 +452,19 @@ public class Workout {
|
|||||||
this.rawHeader = container.getBytes(0x04);
|
this.rawHeader = container.getBytes(0x04);
|
||||||
this.rawData = container.getBytes(0x05); // TODO: not sure if 5 can also be omitted
|
this.rawData = container.getBytes(0x05); // TODO: not sure if 5 can also be omitted
|
||||||
|
|
||||||
if (container.contains(0x09))
|
if (container.contains(0x08))
|
||||||
innerBitmap = container.getShort(0x09);
|
this.extraDataLength = container.getAsInteger(0x08);
|
||||||
else
|
|
||||||
innerBitmap = 0x01FF; // This seems to be the default
|
|
||||||
|
|
||||||
|
if (container.contains(0x09))
|
||||||
|
this.innerBitmap = container.getAsInteger(0x09);
|
||||||
|
else
|
||||||
|
this.innerBitmap = 0x01FF; // This seems to be the default
|
||||||
|
|
||||||
|
|
||||||
|
if (this.rawHeader.length != 14)
|
||||||
|
throw new LengthMismatchException("Workout data header length mismatch.");
|
||||||
|
|
||||||
|
// Calculate inner data length
|
||||||
int innerDataLength = 0;
|
int innerDataLength = 0;
|
||||||
for (byte i = 0; i < innerBitmapLengths.length; i++) {
|
for (byte i = 0; i < innerBitmapLengths.length; i++) {
|
||||||
if ((innerBitmap & (1 << i)) != 0) {
|
if ((innerBitmap & (1 << i)) != 0) {
|
||||||
@ -428,8 +472,9 @@ public class Workout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.rawHeader.length != 14)
|
//TODO: innerDataLength should be equal to this.extraDataLength. Should correlate to innerBitmap default value.
|
||||||
throw new LengthMismatchException("Workout data header length mismatch.");
|
//TODO: I suppose innerBitmap should be 0 by default but not sure and don't have devices for testing. So I do not add this check.
|
||||||
|
//TODO: is is possible that innerBitmap = 0x01FF only true for AW70 devices. in this case extraDataLength should be properly calculated.
|
||||||
|
|
||||||
this.header = new Header();
|
this.header = new Header();
|
||||||
ByteBuffer buf = ByteBuffer.wrap(this.rawHeader);
|
ByteBuffer buf = ByteBuffer.wrap(this.rawHeader);
|
||||||
@ -517,7 +562,40 @@ public class Workout {
|
|||||||
data.backFootLanding = buf.get();
|
data.backFootLanding = buf.get();
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
data.eversionAngle = buf.get();
|
data.eversionAngle = buf.get(); // buf.get() - 100;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
data.hangTime = buf.getShort();
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
data.impactHangRate = buf.getShort();
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
data.rideCadence = buf.get();
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
data.ap = (float) buf.getShort() / 10.0f;
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
data.vo = (float) buf.getShort() / 10.0f;
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
data.gtb = (float) buf.getShort() / 100.0f;
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
data.vr = (float) buf.getShort() / 10.0f;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
data.ceiling = buf.get();
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
data.temp = buf.get();
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
data.spo2 = buf.get();
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
data.cns = buf.getShort();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
data.unknownData = this.tlv.serialize();
|
data.unknownData = this.tlv.serialize();
|
||||||
@ -586,6 +664,7 @@ public class Workout {
|
|||||||
public short correction = 0;
|
public short correction = 0;
|
||||||
public boolean hasCorrection = false;
|
public boolean hasCorrection = false;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Block{" +
|
return "Block{" +
|
||||||
@ -663,25 +742,24 @@ public class Workout {
|
|||||||
public int pace = -1;
|
public int pace = -1;
|
||||||
public short pointIndex = 0;
|
public short pointIndex = 0;
|
||||||
public short segment = -1;
|
public short segment = -1;
|
||||||
public byte swimType= -1;
|
public byte swimType = -1;
|
||||||
public short strokes = -1;
|
public short strokes = -1;
|
||||||
public short avgSwolf = -1;
|
public short avgSwolf = -1;
|
||||||
public int time= -1;
|
public int time = -1;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
final StringBuffer sb = new StringBuffer("Block{");
|
return "Block{" + "distance=" + distance +
|
||||||
sb.append("distance=").append(distance);
|
", type=" + type +
|
||||||
sb.append(", type=").append(type);
|
", pace=" + pace +
|
||||||
sb.append(", pace=").append(pace);
|
", pointIndex=" + pointIndex +
|
||||||
sb.append(", pointIndex=").append(pointIndex);
|
", segment=" + segment +
|
||||||
sb.append(", segment=").append(segment);
|
", swimType=" + swimType +
|
||||||
sb.append(", swimType=").append(swimType);
|
", strokes=" + strokes +
|
||||||
sb.append(", strokes=").append(strokes);
|
", awgSwolf=" + avgSwolf +
|
||||||
sb.append(", awgSwolf=").append(avgSwolf);
|
", time=" + time +
|
||||||
sb.append(", time=").append(time);
|
'}';
|
||||||
sb.append('}');
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,13 +790,13 @@ public class Workout {
|
|||||||
if (blockTlv.contains(0x09))
|
if (blockTlv.contains(0x09))
|
||||||
block.segment = blockTlv.getShort(0x09);
|
block.segment = blockTlv.getShort(0x09);
|
||||||
if (blockTlv.contains(0x0a))
|
if (blockTlv.contains(0x0a))
|
||||||
block.swimType= blockTlv.getByte(0x0a);
|
block.swimType = blockTlv.getByte(0x0a);
|
||||||
if (blockTlv.contains(0x0b))
|
if (blockTlv.contains(0x0b))
|
||||||
block.strokes = blockTlv.getShort(0x0b);
|
block.strokes = blockTlv.getShort(0x0b);
|
||||||
if (blockTlv.contains(0x0c))
|
if (blockTlv.contains(0x0c))
|
||||||
block.avgSwolf = blockTlv.getShort(0x0c);
|
block.avgSwolf = blockTlv.getShort(0x0c);
|
||||||
if (blockTlv.contains(0x0d))
|
if (blockTlv.contains(0x0d))
|
||||||
block.time= blockTlv.getInteger(0x0d);
|
block.time = blockTlv.getInteger(0x0d);
|
||||||
|
|
||||||
blocks.add(block);
|
blocks.add(block);
|
||||||
}
|
}
|
||||||
@ -758,11 +836,9 @@ public class Workout {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
final StringBuffer sb = new StringBuffer("Block{");
|
return "Block{" + "interval=" + interval +
|
||||||
sb.append("interval=").append(interval);
|
", value=" + value +
|
||||||
sb.append(", value=").append(value);
|
'}';
|
||||||
sb.append('}');
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,6 +873,179 @@ public class Workout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class WorkoutCapability {
|
||||||
|
public static final int id = 0x15;
|
||||||
|
|
||||||
|
public static class Request extends HuaweiPacket {
|
||||||
|
|
||||||
|
public Request(
|
||||||
|
ParamsProvider paramsProvider
|
||||||
|
) {
|
||||||
|
super(paramsProvider);
|
||||||
|
|
||||||
|
this.serviceId = Workout.id;
|
||||||
|
this.commandId = id;
|
||||||
|
|
||||||
|
this.tlv = new HuaweiTLV()
|
||||||
|
.put(0x01);
|
||||||
|
|
||||||
|
this.complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends HuaweiPacket {
|
||||||
|
public boolean supportNewStep = false;
|
||||||
|
|
||||||
|
public Response(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws ParseException {
|
||||||
|
if (this.tlv.contains(0x01)) {
|
||||||
|
int flags = this.tlv.getAsInteger(0x01);
|
||||||
|
supportNewStep = (flags & 2) == 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WorkoutSections {
|
||||||
|
public static final int id = 0x16;
|
||||||
|
|
||||||
|
public static class Request extends HuaweiPacket {
|
||||||
|
|
||||||
|
public Request(
|
||||||
|
ParamsProvider paramsProvider,
|
||||||
|
short workoutNumber,
|
||||||
|
short additionalDataNumber
|
||||||
|
) {
|
||||||
|
super(paramsProvider);
|
||||||
|
|
||||||
|
this.serviceId = Workout.id;
|
||||||
|
this.commandId = id;
|
||||||
|
|
||||||
|
this.tlv = new HuaweiTLV()
|
||||||
|
.put(0x01, workoutNumber)
|
||||||
|
.put(0x02, additionalDataNumber)
|
||||||
|
.put(0x03);
|
||||||
|
|
||||||
|
this.complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends HuaweiPacket {
|
||||||
|
public static class Block {
|
||||||
|
public int num = -1;
|
||||||
|
public long time = -1;
|
||||||
|
public long distance = -1;
|
||||||
|
public int pace = -1;
|
||||||
|
public int heartRate = -1;
|
||||||
|
public int cadence = -1;
|
||||||
|
public int stepLength = -1;
|
||||||
|
public long totalRise = -1;
|
||||||
|
public long totalDescend = -1;
|
||||||
|
public int groundContactTime = -1;
|
||||||
|
public int groundImpact = -1;
|
||||||
|
public int swingAngle = -1;
|
||||||
|
public int eversion = -1;
|
||||||
|
|
||||||
|
public int avgCadence = -1;
|
||||||
|
public int intervalTrainingType = -1;
|
||||||
|
public int divingMaxDepth = -1;
|
||||||
|
public int divingUnderwaterTime = -1;
|
||||||
|
public int divingBreakTime = -1;
|
||||||
|
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Block{" + "num=" + num +
|
||||||
|
", time=" + time +
|
||||||
|
", distance=" + distance +
|
||||||
|
", pace=" + pace +
|
||||||
|
", heartRate=" + heartRate +
|
||||||
|
", cadence=" + cadence +
|
||||||
|
", stepLength=" + stepLength +
|
||||||
|
", totalRise=" + totalRise +
|
||||||
|
", totalDescend=" + totalDescend +
|
||||||
|
", groundContactTime=" + groundContactTime +
|
||||||
|
", groundImpact=" + groundImpact +
|
||||||
|
", swingAngle=" + swingAngle +
|
||||||
|
", eversion=" + eversion +
|
||||||
|
", avgCadence=" + avgCadence +
|
||||||
|
", intervalTrainingType=" + intervalTrainingType +
|
||||||
|
", divingMaxDepth=" + divingMaxDepth +
|
||||||
|
", divingUnderwaterTime=" + divingUnderwaterTime +
|
||||||
|
", divingBreakTime=" + divingBreakTime +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public short workoutId;
|
||||||
|
public short number; //TODO: meaning of this field
|
||||||
|
public List<Block> blocks;
|
||||||
|
|
||||||
|
public Response(ParamsProvider paramsProvider) {
|
||||||
|
super(paramsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseTlv() throws ParseException {
|
||||||
|
|
||||||
|
this.workoutId = this.tlv.getShort(0x01);
|
||||||
|
this.number = this.tlv.getShort(0x02);
|
||||||
|
|
||||||
|
HuaweiTLV container = this.tlv.getObject(0x83);
|
||||||
|
|
||||||
|
this.blocks = new ArrayList<>();
|
||||||
|
for (HuaweiTLV blockTlv : container.getObjects(0x84)) {
|
||||||
|
Block block = new Block();
|
||||||
|
|
||||||
|
if (blockTlv.contains(0x05))
|
||||||
|
block.num = blockTlv.getAsInteger(0x05);
|
||||||
|
if (blockTlv.contains(0x06))
|
||||||
|
block.time = blockTlv.getAsLong(0x06);
|
||||||
|
if (blockTlv.contains(0x07))
|
||||||
|
block.distance = blockTlv.getAsLong(0x07);
|
||||||
|
if (blockTlv.contains(0x08))
|
||||||
|
block.pace = blockTlv.getAsInteger(0x08);
|
||||||
|
if (blockTlv.contains(0x09))
|
||||||
|
block.heartRate = blockTlv.getAsInteger(0x09);
|
||||||
|
if (blockTlv.contains(0xa))
|
||||||
|
block.cadence = blockTlv.getAsInteger(0xa);
|
||||||
|
if (blockTlv.contains(0xb))
|
||||||
|
block.stepLength = blockTlv.getAsInteger(0xb);
|
||||||
|
if (blockTlv.contains(0xc))
|
||||||
|
block.totalRise = blockTlv.getAsLong(0xc);
|
||||||
|
if (blockTlv.contains(0xd))
|
||||||
|
block.totalDescend = blockTlv.getAsLong(0xd);
|
||||||
|
if (blockTlv.contains(0xe))
|
||||||
|
block.groundContactTime = blockTlv.getAsInteger(0xe);
|
||||||
|
if (blockTlv.contains(0xf))
|
||||||
|
block.groundImpact = blockTlv.getAsInteger(0xf);
|
||||||
|
if (blockTlv.contains(0x10))
|
||||||
|
block.swingAngle = blockTlv.getAsInteger(0x10);
|
||||||
|
if (blockTlv.contains(0x11))
|
||||||
|
block.eversion = blockTlv.getAsInteger(0x11);
|
||||||
|
|
||||||
|
if (blockTlv.contains(0x22))
|
||||||
|
block.avgCadence = blockTlv.getAsInteger(0x22);
|
||||||
|
if (blockTlv.contains(0x23))
|
||||||
|
block.intervalTrainingType = blockTlv.getAsInteger(0x23);
|
||||||
|
if (blockTlv.contains(0x28))
|
||||||
|
block.divingMaxDepth = blockTlv.getAsInteger(0x28);
|
||||||
|
if (blockTlv.contains(0x29))
|
||||||
|
block.divingUnderwaterTime = blockTlv.getAsInteger(0x29);
|
||||||
|
if (blockTlv.contains(0x2a))
|
||||||
|
block.divingBreakTime = blockTlv.getAsInteger(0x2a);
|
||||||
|
|
||||||
|
blocks.add(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class NotifyHeartRate {
|
public static class NotifyHeartRate {
|
||||||
public static final int id = 0x17;
|
public static final int id = 0x17;
|
||||||
|
|
||||||
|
@ -80,6 +80,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSample;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSampleDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSampleDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSample;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSectionsSample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSectionsSampleDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSpO2Sample;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSpO2Sample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSpO2SampleDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSpO2SampleDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample;
|
||||||
@ -128,6 +130,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetN
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetOTAChangeLog;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetOTAChangeLog;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetSmartAlarmList;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetSmartAlarmList;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetWatchfaceParams;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetWatchfaceParams;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetWorkoutCapability;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendCameraRemoteSetupEvent;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendCameraRemoteSetupEvent;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendDeviceReportThreshold;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendDeviceReportThreshold;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendExtendedAccountRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendExtendedAccountRequest;
|
||||||
@ -856,6 +859,7 @@ public class HuaweiSupportProvider {
|
|||||||
initRequestQueue.add(new GetContactsCount(this));
|
initRequestQueue.add(new GetContactsCount(this));
|
||||||
initRequestQueue.add(new SendOTASetAutoUpdate(this));
|
initRequestQueue.add(new SendOTASetAutoUpdate(this));
|
||||||
initRequestQueue.add(new GetOTAChangeLog(this));
|
initRequestQueue.add(new GetOTAChangeLog(this));
|
||||||
|
//initRequestQueue.add(new GetWorkoutCapability(this)); // TODO: in current stage I don't understand how to parse new steps.
|
||||||
initRequestQueue.add(new GetEventAlarmList(this));
|
initRequestQueue.add(new GetEventAlarmList(this));
|
||||||
initRequestQueue.add(new GetSmartAlarmList(this));
|
initRequestQueue.add(new GetSmartAlarmList(this));
|
||||||
|
|
||||||
@ -1821,7 +1825,18 @@ public class HuaweiSupportProvider {
|
|||||||
data.calories,
|
data.calories,
|
||||||
data.cyclingPower,
|
data.cyclingPower,
|
||||||
data.frequency,
|
data.frequency,
|
||||||
data.altitude
|
data.altitude,
|
||||||
|
data.hangTime,
|
||||||
|
data.impactHangRate,
|
||||||
|
data.rideCadence,
|
||||||
|
data.ap,
|
||||||
|
data.vo,
|
||||||
|
data.gtb,
|
||||||
|
data.vr,
|
||||||
|
data.ceiling,
|
||||||
|
data.temp,
|
||||||
|
data.spo2,
|
||||||
|
data.cns
|
||||||
);
|
);
|
||||||
dao.insertOrReplace(dataSample);
|
dao.insertOrReplace(dataSample);
|
||||||
}
|
}
|
||||||
@ -1928,6 +1943,54 @@ public class HuaweiSupportProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addWorkoutSectionsData(Long workoutId, List<Workout.WorkoutSections.Response.Block> spO2List, short number) {
|
||||||
|
if (workoutId == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// NOTE: All fields of this data is optional. At this point I don't all workouts that this data used.
|
||||||
|
// I decided to add two additional fields dataIdx and rowIdx as primary keys that should identify each row
|
||||||
|
try (DBHandler db = GBApplication.acquireDB()) {
|
||||||
|
HuaweiWorkoutSectionsSampleDao dao = db.getDaoSession().getHuaweiWorkoutSectionsSampleDao();
|
||||||
|
|
||||||
|
if (number == 0) {
|
||||||
|
final DeleteQuery<HuaweiWorkoutSectionsSample> tableDeleteQuery = dao.queryBuilder()
|
||||||
|
.where(HuaweiWorkoutSectionsSampleDao.Properties.WorkoutId.eq(workoutId))
|
||||||
|
.buildDelete();
|
||||||
|
tableDeleteQuery.executeDeleteWithoutDetachingEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (Workout.WorkoutSections.Response.Block block : spO2List) {
|
||||||
|
HuaweiWorkoutSectionsSample huaweiWorkoutSectionsSample = new HuaweiWorkoutSectionsSample(
|
||||||
|
workoutId,
|
||||||
|
number,
|
||||||
|
i++,
|
||||||
|
block.num,
|
||||||
|
block.time,
|
||||||
|
block.distance,
|
||||||
|
block.pace,
|
||||||
|
block.heartRate,
|
||||||
|
block.cadence,
|
||||||
|
block.stepLength,
|
||||||
|
block.totalRise,
|
||||||
|
block.totalDescend,
|
||||||
|
block.groundContactTime,
|
||||||
|
block.groundImpact,
|
||||||
|
block.swingAngle,
|
||||||
|
block.eversion,
|
||||||
|
block.avgCadence,
|
||||||
|
block.divingUnderwaterTime,
|
||||||
|
block.divingMaxDepth,
|
||||||
|
block.divingUnderwaterTime,
|
||||||
|
block.divingBreakTime
|
||||||
|
);
|
||||||
|
dao.insertOrReplace(huaweiWorkoutSectionsSample);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Failed to add workout sections data to database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addDictData(List<HuaweiP2PDataDictionarySyncService.DictData> dictData) {
|
public void addDictData(List<HuaweiP2PDataDictionarySyncService.DictData> dictData) {
|
||||||
try (DBHandler db = GBApplication.acquireDB()) {
|
try (DBHandler db = GBApplication.acquireDB()) {
|
||||||
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
||||||
|
@ -301,7 +301,18 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
|
|||||||
responseData.calories,
|
responseData.calories,
|
||||||
responseData.cyclingPower,
|
responseData.cyclingPower,
|
||||||
responseData.frequency,
|
responseData.frequency,
|
||||||
responseData.altitude
|
responseData.altitude,
|
||||||
|
responseData.hangTime,
|
||||||
|
responseData.impactHangRate,
|
||||||
|
responseData.rideCadence,
|
||||||
|
responseData.ap,
|
||||||
|
responseData.vo,
|
||||||
|
responseData.gtb,
|
||||||
|
responseData.vr,
|
||||||
|
responseData.ceiling,
|
||||||
|
responseData.temp,
|
||||||
|
responseData.spo2,
|
||||||
|
responseData.cns
|
||||||
);
|
);
|
||||||
|
|
||||||
dbHandler.getDaoSession().getHuaweiWorkoutDataSampleDao().insertOrReplace(dataSample);
|
dbHandler.getDaoSession().getHuaweiWorkoutDataSampleDao().insertOrReplace(dataSample);
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Workout;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
|
||||||
|
public class GetWorkoutCapability extends Request {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GetWorkoutCapability.class);
|
||||||
|
|
||||||
|
public GetWorkoutCapability(HuaweiSupportProvider support) {
|
||||||
|
super(support);
|
||||||
|
this.serviceId = Workout.id;
|
||||||
|
this.commandId = Workout.WorkoutCapability.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean requestSupported() {
|
||||||
|
return supportProvider.getHuaweiCoordinator().supportsWorkoutCapability();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new Workout.WorkoutCapability.Request(paramsProvider).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processResponse() throws ResponseParseException {
|
||||||
|
LOG.debug("handle WorkoutCapability");
|
||||||
|
if (!(receivedPacket instanceof Workout.WorkoutCapability.Response))
|
||||||
|
throw new ResponseTypeMismatchException(receivedPacket, Workout.WorkoutCapability.Response.class);
|
||||||
|
|
||||||
|
LOG.info("Workout capability: NewSteps: {}", ((Workout.WorkoutCapability.Response) receivedPacket).supportNewStep);
|
||||||
|
|
||||||
|
supportProvider.getHuaweiCoordinator().setSupportsWorkoutNewSteps(((Workout.WorkoutCapability.Response) receivedPacket).supportNewStep);
|
||||||
|
}
|
||||||
|
}
|
@ -60,7 +60,7 @@ public class GetWorkoutDataRequest extends Request {
|
|||||||
@Override
|
@Override
|
||||||
protected List<byte[]> createRequest() throws RequestCreationException {
|
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||||
try {
|
try {
|
||||||
return new Workout.WorkoutData.Request(paramsProvider, workoutNumbers.workoutNumber, this.number).serialize();
|
return new Workout.WorkoutData.Request(paramsProvider, workoutNumbers.workoutNumber, this.number, supportProvider.getHuaweiCoordinator().isSupportsWorkoutNewSteps()).serialize();
|
||||||
} catch (HuaweiPacket.CryptoException e) {
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
throw new RequestCreationException(e);
|
throw new RequestCreationException(e);
|
||||||
}
|
}
|
||||||
@ -133,6 +133,16 @@ public class GetWorkoutDataRequest extends Request {
|
|||||||
);
|
);
|
||||||
nextRequest.setFinalizeReq(this.finalizeReq);
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
this.nextRequest(nextRequest);
|
this.nextRequest(nextRequest);
|
||||||
|
} else if (this.workoutNumbers.sectionsCount > 0) {
|
||||||
|
GetWorkoutSectionsRequest nextRequest = new GetWorkoutSectionsRequest(
|
||||||
|
this.supportProvider,
|
||||||
|
this.workoutNumbers,
|
||||||
|
this.remainder,
|
||||||
|
(short) 0,
|
||||||
|
this.databaseId
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
|
this.nextRequest(nextRequest);
|
||||||
} else {
|
} else {
|
||||||
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(this.databaseId);
|
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(this.databaseId);
|
||||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
||||||
|
@ -109,6 +109,16 @@ public class GetWorkoutPaceRequest extends Request {
|
|||||||
);
|
);
|
||||||
nextRequest.setFinalizeReq(this.finalizeReq);
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
this.nextRequest(nextRequest);
|
this.nextRequest(nextRequest);
|
||||||
|
} else if (this.workoutNumbers.sectionsCount > 0) {
|
||||||
|
GetWorkoutSectionsRequest nextRequest = new GetWorkoutSectionsRequest(
|
||||||
|
this.supportProvider,
|
||||||
|
this.workoutNumbers,
|
||||||
|
this.remainder,
|
||||||
|
(short) 0,
|
||||||
|
this.databaseId
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
|
this.nextRequest(nextRequest);
|
||||||
} else {
|
} else {
|
||||||
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(this.databaseId);
|
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(this.databaseId);
|
||||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Workout;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiWorkoutGbParser;
|
||||||
|
|
||||||
|
public class GetWorkoutSectionsRequest extends Request {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GetWorkoutSectionsRequest.class);
|
||||||
|
|
||||||
|
Workout.WorkoutCount.Response.WorkoutNumbers workoutNumbers;
|
||||||
|
List<Workout.WorkoutCount.Response.WorkoutNumbers> remainder;
|
||||||
|
short number;
|
||||||
|
Long databaseId;
|
||||||
|
|
||||||
|
public GetWorkoutSectionsRequest(HuaweiSupportProvider support, Workout.WorkoutCount.Response.WorkoutNumbers workoutNumbers, List<Workout.WorkoutCount.Response.WorkoutNumbers> remainder, short number, Long databaseId) {
|
||||||
|
super(support);
|
||||||
|
|
||||||
|
this.serviceId = Workout.id;
|
||||||
|
this.commandId = Workout.WorkoutSections.id;
|
||||||
|
|
||||||
|
this.workoutNumbers = workoutNumbers;
|
||||||
|
this.remainder = remainder;
|
||||||
|
this.number = number;
|
||||||
|
|
||||||
|
this.databaseId = databaseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<byte[]> createRequest() throws RequestCreationException {
|
||||||
|
try {
|
||||||
|
return new Workout.WorkoutSections.Request(paramsProvider, this.workoutNumbers.workoutNumber, this.number).serialize();
|
||||||
|
} catch (HuaweiPacket.CryptoException e) {
|
||||||
|
throw new RequestCreationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processResponse() throws ResponseParseException {
|
||||||
|
if (!(receivedPacket instanceof Workout.WorkoutSections.Response))
|
||||||
|
throw new ResponseTypeMismatchException(receivedPacket, Workout.WorkoutSections.Response.class);
|
||||||
|
|
||||||
|
Workout.WorkoutSections.Response packet = (Workout.WorkoutSections.Response) receivedPacket;
|
||||||
|
|
||||||
|
|
||||||
|
LOG.info("Workout {} section {}:", this.workoutNumbers.workoutNumber, this.number);
|
||||||
|
LOG.info("workoutId : {}", packet.workoutId);
|
||||||
|
LOG.info("number : {}", packet.number);
|
||||||
|
LOG.info("Block num : {}", packet.blocks.size());
|
||||||
|
LOG.info("Blocks : {}", Arrays.toString(packet.blocks.toArray()));
|
||||||
|
|
||||||
|
supportProvider.addWorkoutSectionsData(this.databaseId, packet.blocks, this.number);
|
||||||
|
|
||||||
|
if (this.workoutNumbers.sectionsCount > this.number + 1) {
|
||||||
|
GetWorkoutSectionsRequest nextRequest = new GetWorkoutSectionsRequest(
|
||||||
|
this.supportProvider,
|
||||||
|
this.workoutNumbers,
|
||||||
|
this.remainder,
|
||||||
|
(short) (this.number + 1),
|
||||||
|
this.databaseId
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
|
this.nextRequest(nextRequest);
|
||||||
|
} else {
|
||||||
|
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(this.databaseId);
|
||||||
|
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!remainder.isEmpty()) {
|
||||||
|
GetWorkoutTotalsRequest nextRequest = new GetWorkoutTotalsRequest(
|
||||||
|
GetWorkoutSectionsRequest.this.supportProvider,
|
||||||
|
remainder.remove(0),
|
||||||
|
remainder
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(GetWorkoutSectionsRequest.this.finalizeReq);
|
||||||
|
// Cannot do this with nextRequest because it's in a callback
|
||||||
|
try {
|
||||||
|
nextRequest.doPerform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
finalizeReq.handleException(new ResponseParseException("Cannot send next request", e));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
supportProvider.endOfWorkoutSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -45,7 +45,7 @@ public class GetWorkoutSpO2Request extends Request {
|
|||||||
@Override
|
@Override
|
||||||
protected void processResponse() throws ResponseParseException {
|
protected void processResponse() throws ResponseParseException {
|
||||||
if (!(receivedPacket instanceof Workout.WorkoutSpO2.Response))
|
if (!(receivedPacket instanceof Workout.WorkoutSpO2.Response))
|
||||||
throw new ResponseTypeMismatchException(receivedPacket, Workout.WorkoutSwimSegments.Response.class);
|
throw new ResponseTypeMismatchException(receivedPacket, Workout.WorkoutSections.Response.class);
|
||||||
|
|
||||||
Workout.WorkoutSpO2.Response packet = (Workout.WorkoutSpO2.Response) receivedPacket;
|
Workout.WorkoutSpO2.Response packet = (Workout.WorkoutSpO2.Response) receivedPacket;
|
||||||
|
|
||||||
@ -68,6 +68,16 @@ public class GetWorkoutSpO2Request extends Request {
|
|||||||
);
|
);
|
||||||
nextRequest.setFinalizeReq(this.finalizeReq);
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
this.nextRequest(nextRequest);
|
this.nextRequest(nextRequest);
|
||||||
|
} else if (this.workoutNumbers.sectionsCount > 0) {
|
||||||
|
GetWorkoutSectionsRequest nextRequest = new GetWorkoutSectionsRequest(
|
||||||
|
this.supportProvider,
|
||||||
|
this.workoutNumbers,
|
||||||
|
this.remainder,
|
||||||
|
(short) 0,
|
||||||
|
this.databaseId
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
|
this.nextRequest(nextRequest);
|
||||||
} else {
|
} else {
|
||||||
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(this.databaseId);
|
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(this.databaseId);
|
||||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
||||||
|
@ -83,6 +83,16 @@ public class GetWorkoutSwimSegmentsRequest extends Request {
|
|||||||
);
|
);
|
||||||
nextRequest.setFinalizeReq(this.finalizeReq);
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
this.nextRequest(nextRequest);
|
this.nextRequest(nextRequest);
|
||||||
|
} else if (this.workoutNumbers.sectionsCount > 0) {
|
||||||
|
GetWorkoutSectionsRequest nextRequest = new GetWorkoutSectionsRequest(
|
||||||
|
this.supportProvider,
|
||||||
|
this.workoutNumbers,
|
||||||
|
this.remainder,
|
||||||
|
(short) 0,
|
||||||
|
this.databaseId
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
|
this.nextRequest(nextRequest);
|
||||||
} else {
|
} else {
|
||||||
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(this.databaseId);
|
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(this.databaseId);
|
||||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, this.databaseId, new Runnable() {
|
||||||
|
@ -124,6 +124,16 @@ public class GetWorkoutTotalsRequest extends Request {
|
|||||||
);
|
);
|
||||||
nextRequest.setFinalizeReq(this.finalizeReq);
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
this.nextRequest(nextRequest);
|
this.nextRequest(nextRequest);
|
||||||
|
} else if (this.workoutNumbers.sectionsCount > 0) {
|
||||||
|
GetWorkoutSectionsRequest nextRequest = new GetWorkoutSectionsRequest(
|
||||||
|
this.supportProvider,
|
||||||
|
this.workoutNumbers,
|
||||||
|
this.remainder,
|
||||||
|
(short) 0,
|
||||||
|
databaseId
|
||||||
|
);
|
||||||
|
nextRequest.setFinalizeReq(this.finalizeReq);
|
||||||
|
this.nextRequest(nextRequest);
|
||||||
} else {
|
} else {
|
||||||
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(databaseId);
|
new HuaweiWorkoutGbParser(getDevice(), getContext()).parseWorkout(databaseId);
|
||||||
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, databaseId, new Runnable() {
|
supportProvider.downloadWorkoutGpsFiles(this.workoutNumbers.workoutNumber, databaseId, new Runnable() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user