mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Garmin: implement messages 5007/Filter and 5037/Synchronization
This commit does not override the default fetching of activity data, which is still phone-initiated, but adds support for watch-initiated sync as well (typically upon connecting). Also change the order of the messages exchanged upon connection to mimic logs of official app. Also remove some status messages where the outgoing message is already a status. Also send the status "app in foreground" so that the watch can initiate the synchronization.
This commit is contained in:
+13
@@ -41,12 +41,15 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.deviceevents.
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.CreateFileMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.CreateFileMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.DownloadRequestMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.DownloadRequestMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.FileTransferDataMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.FileTransferDataMessage;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.FilterMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.GFDIMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.GFDIMessage;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SynchronizationMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SystemEventMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SystemEventMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.UploadRequestMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.UploadRequestMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.CreateFileStatusMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.CreateFileStatusMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.DownloadRequestStatusMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.DownloadRequestStatusMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.FileTransferDataStatusMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.FileTransferDataStatusMessage;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.FilterStatusMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.UploadRequestStatusMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.UploadRequestStatusMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
@@ -94,6 +97,16 @@ public class FileTransferHandler implements MessageHandler {
|
|||||||
return upload.setUploadRequestStatusMessage((UploadRequestStatusMessage) message);
|
return upload.setUploadRequestStatusMessage((UploadRequestStatusMessage) message);
|
||||||
else if (message instanceof FileTransferDataStatusMessage)
|
else if (message instanceof FileTransferDataStatusMessage)
|
||||||
return upload.processUploadProgress((FileTransferDataStatusMessage) message);
|
return upload.processUploadProgress((FileTransferDataStatusMessage) message);
|
||||||
|
else if (message instanceof SynchronizationMessage)
|
||||||
|
return processSynchronizationMessage((SynchronizationMessage) message);
|
||||||
|
else if (message instanceof FilterStatusMessage)
|
||||||
|
return initiateDownload();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FilterMessage processSynchronizationMessage(SynchronizationMessage message) {
|
||||||
|
if (message.shouldProceed())
|
||||||
|
return new FilterMessage();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-10
@@ -110,6 +110,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SetD
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SetFileFlagsMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SetFileFlagsMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SupportedFileTypesMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SupportedFileTypesMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SystemEventMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SystemEventMessage;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.GenericStatusMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.NotificationSubscriptionStatusMessage;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.NotificationSubscriptionStatusMessage;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.CompressionUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.CompressionUtils;
|
||||||
@@ -295,8 +296,7 @@ public class GarminSupport extends AbstractBTLESingleDeviceSupport implements IC
|
|||||||
return; //message cannot be handled
|
return; //message cannot be handled
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.debug("Got GFDIMessage {} ({} bytes)", parsedMessage.getClass().getSimpleName(), message.length);
|
LOG.debug("INCOMING message: {}/{}: {}", parsedMessage, parsedMessage.getGarminMessage(), GB.hexdump(message));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
the handler elaborates the followup message but might change the status message since it does
|
the handler elaborates the followup message but might change the status message since it does
|
||||||
check the integrity of the incoming message payload. Hence we let the handlers elaborate the
|
check the integrity of the incoming message payload. Hence we let the handlers elaborate the
|
||||||
@@ -317,13 +317,13 @@ public class GarminSupport extends AbstractBTLESingleDeviceSupport implements IC
|
|||||||
evaluateGBDeviceEvent(event);
|
evaluateGBDeviceEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
communicator.sendMessage("send status", parsedMessage.getAckBytestream()); //send status message
|
sendAck("send status", parsedMessage); //send status message
|
||||||
|
|
||||||
sendOutgoingMessage("send reply", parsedMessage); //send reply if any
|
sendOutgoingMessage("send reply", parsedMessage); //send reply if any
|
||||||
|
|
||||||
sendOutgoingMessage("send followup", followup); //send followup message if any
|
sendOutgoingMessage("send followup", followup); //send followup message if any
|
||||||
|
|
||||||
if (parsedMessage instanceof ConfigurationMessage) { //the last forced message exchange
|
if (parsedMessage instanceof GenericStatusMessage && ((GenericStatusMessage) parsedMessage).getGarminMessage() == GFDIMessage.GarminMessage.CONFIGURATION) { //the last forced message exchange
|
||||||
completeInitialization();
|
completeInitialization();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,6 +477,10 @@ public class GarminSupport extends AbstractBTLESingleDeviceSupport implements IC
|
|||||||
// We initiate download here even in the new sync protocol so that the watch "flushes" the data
|
// We initiate download here even in the new sync protocol so that the watch "flushes" the data
|
||||||
// otherwise we might get incomplete monitor files
|
// otherwise we might get incomplete monitor files
|
||||||
sendOutgoingMessage("fetch recorded data", fileTransferHandler.initiateDownload());
|
sendOutgoingMessage("fetch recorded data", fileTransferHandler.initiateDownload());
|
||||||
|
|
||||||
|
//TODO: ask the watch to initiate the sync? Something like:
|
||||||
|
// sendOutgoingMessage("set sync ready", new SystemEventMessage(SystemEventMessage.GarminSystemEventType.SYNC_READY, 0));
|
||||||
|
// sendOutgoingMessage("set foreground", new SystemEventMessage(SystemEventMessage.GarminSystemEventType.HOST_DID_ENTER_FOREGROUND, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean newSyncProtocol() {
|
public boolean newSyncProtocol() {
|
||||||
@@ -598,9 +602,19 @@ public class GarminSupport extends AbstractBTLESingleDeviceSupport implements IC
|
|||||||
private void sendOutgoingMessage(final String taskName, final GFDIMessage message) {
|
private void sendOutgoingMessage(final String taskName, final GFDIMessage message) {
|
||||||
if (message == null)
|
if (message == null)
|
||||||
return;
|
return;
|
||||||
|
if (message.getOutgoingMessage() != null)
|
||||||
|
LOG.debug("OUTGOING message {}: {}", message, GB.hexdump(message.getOutgoingMessage()));
|
||||||
communicator.sendMessage(taskName, message.getOutgoingMessage());
|
communicator.sendMessage(taskName, message.getOutgoingMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendAck(final String taskName, final GFDIMessage message) {
|
||||||
|
if (message == null)
|
||||||
|
return;
|
||||||
|
if (message.getAckBytestream() != null)
|
||||||
|
LOG.debug("OUTGOING ACK {}: {}", message, GB.hexdump(message.getAckBytestream()));
|
||||||
|
communicator.sendMessage(taskName, message.getAckBytestream());
|
||||||
|
}
|
||||||
|
|
||||||
private void sendWeatherConditions(WeatherSpec weather) {
|
private void sendWeatherConditions(WeatherSpec weather) {
|
||||||
if (!getCoordinator().supports(getDevice(), GarminCapability.WEATHER_CONDITIONS)) {
|
if (!getCoordinator().supports(getDevice(), GarminCapability.WEATHER_CONDITIONS)) {
|
||||||
// Device does not support sending weather as fit
|
// Device does not support sending weather as fit
|
||||||
@@ -708,19 +722,23 @@ public class GarminSupport extends AbstractBTLESingleDeviceSupport implements IC
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void completeInitialization() {
|
private void completeInitialization() {
|
||||||
|
sendOutgoingMessage("request supported file types", new SupportedFileTypesMessage());
|
||||||
|
sendDeviceSettings();
|
||||||
|
|
||||||
if (GBApplication.getPrefs().syncTime()) {
|
if (GBApplication.getPrefs().syncTime()) {
|
||||||
onSetTime();
|
onSetTime();
|
||||||
}
|
}
|
||||||
enableWeather();
|
|
||||||
|
|
||||||
//following is needed for vivomove style
|
//following is needed for vivomove style
|
||||||
sendOutgoingMessage("set sync ready", new SystemEventMessage(SystemEventMessage.GarminSystemEventType.SYNC_READY, 0));
|
sendOutgoingMessage("set sync ready", new SystemEventMessage(SystemEventMessage.GarminSystemEventType.SYNC_READY, 0));
|
||||||
|
|
||||||
enableBatteryLevelUpdate();
|
enableBatteryLevelUpdate();
|
||||||
|
|
||||||
|
sendOutgoingMessage("set foreground", new SystemEventMessage(SystemEventMessage.GarminSystemEventType.HOST_DID_ENTER_FOREGROUND, 0));
|
||||||
|
|
||||||
|
|
||||||
gbDevice.setUpdateState(GBDevice.State.INITIALIZED, getContext());
|
gbDevice.setUpdateState(GBDevice.State.INITIALIZED, getContext());
|
||||||
|
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||||
|
|
||||||
sendOutgoingMessage("request supported file types", new SupportedFileTypesMessage());
|
|
||||||
|
|
||||||
if (mFirstConnect) {
|
if (mFirstConnect) {
|
||||||
sendOutgoingMessage("set sync complete", new SystemEventMessage(SystemEventMessage.GarminSystemEventType.SYNC_COMPLETE, 0));
|
sendOutgoingMessage("set sync complete", new SystemEventMessage(SystemEventMessage.GarminSystemEventType.SYNC_COMPLETE, 0));
|
||||||
@@ -833,6 +851,10 @@ public class GarminSupport extends AbstractBTLESingleDeviceSupport implements IC
|
|||||||
getDevice().sendDeviceUpdateIntent(getContext());
|
getDevice().sendDeviceUpdateIntent(getContext());
|
||||||
}
|
}
|
||||||
isBusyFetching = false;
|
isBusyFetching = false;
|
||||||
|
|
||||||
|
sendOutgoingMessage("set sync complete", new SystemEventMessage(SystemEventMessage.GarminSystemEventType.SYNC_COMPLETE, 0));
|
||||||
|
sendOutgoingMessage("set background", new SystemEventMessage(SystemEventMessage.GarminSystemEventType.HOST_DID_ENTER_BACKGROUND, 0));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -855,6 +877,7 @@ public class GarminSupport extends AbstractBTLESingleDeviceSupport implements IC
|
|||||||
GB.signalActivityDataFinish(getDevice());
|
GB.signalActivityDataFinish(getDevice());
|
||||||
transferNotification.finish();
|
transferNotification.finish();
|
||||||
getDevice().sendDeviceUpdateIntent(getContext());
|
getDevice().sendDeviceUpdateIntent(getContext());
|
||||||
|
isBusyFetching = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -872,12 +895,12 @@ public class GarminSupport extends AbstractBTLESingleDeviceSupport implements IC
|
|||||||
sendOutgoingMessage("enable battery updates", batteryLevelProtobufRequest);
|
sendOutgoingMessage("enable battery updates", batteryLevelProtobufRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableWeather() {
|
private void sendDeviceSettings() {
|
||||||
final Map<SetDeviceSettingsMessage.GarminDeviceSetting, Object> settings = new LinkedHashMap<>(3);
|
final Map<SetDeviceSettingsMessage.GarminDeviceSetting, Object> settings = new LinkedHashMap<>(3);
|
||||||
settings.put(SetDeviceSettingsMessage.GarminDeviceSetting.AUTO_UPLOAD_ENABLED, false);
|
settings.put(SetDeviceSettingsMessage.GarminDeviceSetting.AUTO_UPLOAD_ENABLED, true);
|
||||||
settings.put(SetDeviceSettingsMessage.GarminDeviceSetting.WEATHER_CONDITIONS_ENABLED, true);
|
settings.put(SetDeviceSettingsMessage.GarminDeviceSetting.WEATHER_CONDITIONS_ENABLED, true);
|
||||||
settings.put(SetDeviceSettingsMessage.GarminDeviceSetting.WEATHER_ALERTS_ENABLED, false);
|
settings.put(SetDeviceSettingsMessage.GarminDeviceSetting.WEATHER_ALERTS_ENABLED, false);
|
||||||
sendOutgoingMessage("enable weather", new SetDeviceSettingsMessage(settings));
|
sendOutgoingMessage("send device settings", new SetDeviceSettingsMessage(settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+8
-2
@@ -27,8 +27,9 @@ public class DeviceInformationMessage extends GFDIMessage {
|
|||||||
private final String deviceName;
|
private final String deviceName;
|
||||||
private final String deviceModel;
|
private final String deviceModel;
|
||||||
// dual-pairing flags & MAC addresses...
|
// dual-pairing flags & MAC addresses...
|
||||||
|
private final boolean generateOutgoing;
|
||||||
|
|
||||||
public DeviceInformationMessage(GarminMessage garminMessage, int protocolVersion, int productNumber, String unitNumber, int softwareVersion, int maxPacketSize, String bluetoothFriendlyName, String deviceName, String deviceModel) {
|
public DeviceInformationMessage(GarminMessage garminMessage, int protocolVersion, int productNumber, String unitNumber, int softwareVersion, int maxPacketSize, String bluetoothFriendlyName, String deviceName, String deviceModel, boolean generateOutgoing) {
|
||||||
this.garminMessage = garminMessage;
|
this.garminMessage = garminMessage;
|
||||||
this.incomingProtocolVersion = protocolVersion;
|
this.incomingProtocolVersion = protocolVersion;
|
||||||
this.incomingProductNumber = productNumber;
|
this.incomingProductNumber = productNumber;
|
||||||
@@ -41,6 +42,11 @@ public class DeviceInformationMessage extends GFDIMessage {
|
|||||||
|
|
||||||
GFDIMessage.setMaxPacketSize(maxPacketSize);
|
GFDIMessage.setMaxPacketSize(maxPacketSize);
|
||||||
this.statusMessage = getStatusMessage();
|
this.statusMessage = getStatusMessage();
|
||||||
|
this.generateOutgoing = generateOutgoing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceInformationMessage(GarminMessage garminMessage, int protocolVersion, int productNumber, String unitNumber, int softwareVersion, int maxPacketSize, String bluetoothFriendlyName, String deviceName, String deviceModel) {
|
||||||
|
this(garminMessage, protocolVersion, productNumber, unitNumber, softwareVersion, maxPacketSize, bluetoothFriendlyName, deviceName, deviceModel, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DeviceInformationMessage parseIncoming(MessageReader reader, GarminMessage garminMessage) {
|
public static DeviceInformationMessage parseIncoming(MessageReader reader, GarminMessage garminMessage) {
|
||||||
@@ -82,7 +88,7 @@ public class DeviceInformationMessage extends GFDIMessage {
|
|||||||
writer.writeString(Build.MANUFACTURER);
|
writer.writeString(Build.MANUFACTURER);
|
||||||
writer.writeString(Build.DEVICE);
|
writer.writeString(Build.DEVICE);
|
||||||
writer.writeByte(protocolFlags);
|
writer.writeByte(protocolFlags);
|
||||||
return true;
|
return this.generateOutgoing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages;
|
||||||
|
|
||||||
|
public class FilterMessage extends GFDIMessage {
|
||||||
|
|
||||||
|
|
||||||
|
public FilterMessage() {
|
||||||
|
this.garminMessage = GarminMessage.FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean generateOutgoing() {
|
||||||
|
final MessageWriter writer = new MessageWriter(response);
|
||||||
|
writer.writeShort(0); // packet size will be filled below
|
||||||
|
writer.writeShort(this.garminMessage.getId());
|
||||||
|
writer.writeByte(FilterType.UNK_3.ordinal());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FilterType {
|
||||||
|
NO_0,
|
||||||
|
UNK_1,
|
||||||
|
UNK_2,
|
||||||
|
UNK_3
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-2
@@ -58,6 +58,10 @@ public abstract class GFDIMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GarminMessage getGarminMessage() {
|
||||||
|
return garminMessage;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract boolean generateOutgoing();
|
protected abstract boolean generateOutgoing();
|
||||||
|
|
||||||
public byte[] getOutgoingMessage() {
|
public byte[] getOutgoingMessage() {
|
||||||
@@ -100,6 +104,7 @@ public abstract class GFDIMessage {
|
|||||||
UPLOAD_REQUEST(5003, UploadRequestMessage.class),
|
UPLOAD_REQUEST(5003, UploadRequestMessage.class),
|
||||||
FILE_TRANSFER_DATA(5004, FileTransferDataMessage.class),
|
FILE_TRANSFER_DATA(5004, FileTransferDataMessage.class),
|
||||||
CREATE_FILE(5005, CreateFileMessage.class),
|
CREATE_FILE(5005, CreateFileMessage.class),
|
||||||
|
FILTER(5007, FilterMessage.class),
|
||||||
SET_FILE_FLAG(5008, SetFileFlagsMessage.class),
|
SET_FILE_FLAG(5008, SetFileFlagsMessage.class),
|
||||||
FIT_DEFINITION(5011, FitDefinitionMessage.class),
|
FIT_DEFINITION(5011, FitDefinitionMessage.class),
|
||||||
FIT_DATA(5012, FitDataMessage.class),
|
FIT_DATA(5012, FitDataMessage.class),
|
||||||
@@ -112,6 +117,7 @@ public abstract class GFDIMessage {
|
|||||||
NOTIFICATION_CONTROL(5034, NotificationControlMessage.class),
|
NOTIFICATION_CONTROL(5034, NotificationControlMessage.class),
|
||||||
NOTIFICATION_DATA(5035, NotificationDataMessage.class),
|
NOTIFICATION_DATA(5035, NotificationDataMessage.class),
|
||||||
NOTIFICATION_SUBSCRIPTION(5036, NotificationSubscriptionMessage.class),
|
NOTIFICATION_SUBSCRIPTION(5036, NotificationSubscriptionMessage.class),
|
||||||
|
SYNCHRONIZATION(5037, SynchronizationMessage.class),
|
||||||
FIND_MY_PHONE_REQUEST(5039, FindMyPhoneRequestMessage.class),
|
FIND_MY_PHONE_REQUEST(5039, FindMyPhoneRequestMessage.class),
|
||||||
FIND_MY_PHONE_CANCEL(5040, FindMyPhoneCancelMessage.class),
|
FIND_MY_PHONE_CANCEL(5040, FindMyPhoneCancelMessage.class),
|
||||||
MUSIC_CONTROL(5041, MusicControlMessage.class),
|
MUSIC_CONTROL(5041, MusicControlMessage.class),
|
||||||
@@ -121,8 +127,7 @@ public abstract class GFDIMessage {
|
|||||||
MUSIC_CONTROL_ENTITY_UPDATE(5049, MusicControlEntityUpdateMessage.class),
|
MUSIC_CONTROL_ENTITY_UPDATE(5049, MusicControlEntityUpdateMessage.class),
|
||||||
CONFIGURATION(5050, ConfigurationMessage.class),
|
CONFIGURATION(5050, ConfigurationMessage.class),
|
||||||
CURRENT_TIME_REQUEST(5052, CurrentTimeRequestMessage.class),
|
CURRENT_TIME_REQUEST(5052, CurrentTimeRequestMessage.class),
|
||||||
AUTH_NEGOTIATION(5101, AuthNegotiationMessage.class)
|
AUTH_NEGOTIATION(5101, AuthNegotiationMessage.class);
|
||||||
;
|
|
||||||
private final Class<? extends GFDIMessage> objectClass;
|
private final Class<? extends GFDIMessage> objectClass;
|
||||||
private final int id;
|
private final int id;
|
||||||
|
|
||||||
|
|||||||
+105
@@ -0,0 +1,105 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.EnumUtils;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
|
|
||||||
|
public class SynchronizationMessage extends GFDIMessage {
|
||||||
|
private final SynchronizationType synchronizationType;
|
||||||
|
private final EnumSet<FileType> syncBitmask;
|
||||||
|
|
||||||
|
public SynchronizationMessage(GarminMessage garminMessage, SynchronizationType synchronizationType, EnumSet<FileType> bitmask) {
|
||||||
|
this.garminMessage = garminMessage;
|
||||||
|
this.synchronizationType = synchronizationType;
|
||||||
|
this.syncBitmask = bitmask;
|
||||||
|
|
||||||
|
this.statusMessage = super.getStatusMessage();
|
||||||
|
|
||||||
|
LOG.debug("type: {}, bitmask: {}", synchronizationType, bitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SynchronizationMessage parseIncoming(MessageReader reader, GarminMessage garminMessage) {
|
||||||
|
final int type = reader.readByte();
|
||||||
|
final SynchronizationType synchronizationType = SynchronizationType.fromCode(type);
|
||||||
|
final int size = reader.readByte();
|
||||||
|
final long bitmask;
|
||||||
|
if (size == 8) {
|
||||||
|
bitmask = reader.readLong();
|
||||||
|
} else if (size == 4) {
|
||||||
|
bitmask = reader.readInt();
|
||||||
|
} else {
|
||||||
|
LOG.warn("SynchronizationMessage bitmask size unexpected, was: {}", size);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final EnumSet<FileType> syncBitmask = EnumUtils.processBitVector(FileType.class, bitmask);
|
||||||
|
return new SynchronizationMessage(garminMessage, synchronizationType, syncBitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldProceed() {
|
||||||
|
return syncBitmask.contains(FileType.WORKOUTS) || syncBitmask.contains(FileType.ACTIVITIES)
|
||||||
|
|| syncBitmask.contains(FileType.ACTIVITY_SUMMARY) || syncBitmask.contains(FileType.SLEEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean generateOutgoing() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SynchronizationType {
|
||||||
|
TYPE_0,
|
||||||
|
TYPE_1,
|
||||||
|
TYPE_2,
|
||||||
|
;
|
||||||
|
|
||||||
|
public static SynchronizationType fromCode(final int code) {
|
||||||
|
for (final SynchronizationType type : SynchronizationType.values()) {
|
||||||
|
if (type.ordinal() == code) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Unknown synchronization type " + code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FileType {
|
||||||
|
unk_0,
|
||||||
|
unk_1,
|
||||||
|
unk_2,
|
||||||
|
WORKOUTS,
|
||||||
|
unk_4,
|
||||||
|
ACTIVITIES,
|
||||||
|
unk_6,
|
||||||
|
unk_7,
|
||||||
|
SOFTWARE_UPDATE,
|
||||||
|
unk_9,
|
||||||
|
unk_10,
|
||||||
|
unk_11,
|
||||||
|
unk_12,
|
||||||
|
unk_13,
|
||||||
|
unk_14,
|
||||||
|
unk_15,
|
||||||
|
unk_16,
|
||||||
|
unk_17,
|
||||||
|
unk_18,
|
||||||
|
unk_19,
|
||||||
|
unk_20,
|
||||||
|
ACTIVITY_SUMMARY,
|
||||||
|
unk_22,
|
||||||
|
unk_23,
|
||||||
|
unk_24,
|
||||||
|
unk_25,
|
||||||
|
SLEEP,
|
||||||
|
unk_27,
|
||||||
|
unk_28,
|
||||||
|
unk_29,
|
||||||
|
unk_30,
|
||||||
|
unk_31,
|
||||||
|
unk_32,
|
||||||
|
unk_33,
|
||||||
|
unk_34,
|
||||||
|
unk_35,
|
||||||
|
unk_36,
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status;
|
||||||
|
|
||||||
|
public class FilterStatusMessage extends GFDIStatusMessage {
|
||||||
|
private final Status status;
|
||||||
|
|
||||||
|
public FilterStatusMessage(GarminMessage garminMessage, Status status, int unk) {
|
||||||
|
this.garminMessage = garminMessage;
|
||||||
|
this.status = status;
|
||||||
|
|
||||||
|
LOG.info("Received ACK for message {}", garminMessage);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FilterStatusMessage parseIncoming(MessageReader reader, GarminMessage garminMessage) {
|
||||||
|
final Status status = Status.fromCode(reader.readByte());
|
||||||
|
|
||||||
|
if (!status.equals(Status.ACK)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final int unk = reader.readByte();
|
||||||
|
|
||||||
|
return new FilterStatusMessage(garminMessage, status, unk);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -34,6 +34,8 @@ public abstract class GFDIStatusMessage extends GFDIMessage {
|
|||||||
return FitDataStatusMessage.parseIncoming(reader, originalGarminMessage);
|
return FitDataStatusMessage.parseIncoming(reader, originalGarminMessage);
|
||||||
} else if (GarminMessage.AUTH_NEGOTIATION.equals(originalGarminMessage)) {
|
} else if (GarminMessage.AUTH_NEGOTIATION.equals(originalGarminMessage)) {
|
||||||
return AuthNegotiationStatusMessage.parseIncoming(reader, originalGarminMessage);
|
return AuthNegotiationStatusMessage.parseIncoming(reader, originalGarminMessage);
|
||||||
|
} else if (GarminMessage.FILTER.equals(originalGarminMessage)) {
|
||||||
|
return FilterStatusMessage.parseIncoming(reader, originalGarminMessage);
|
||||||
} else {
|
} else {
|
||||||
final Status status = Status.fromCode(reader.readByte());
|
final Status status = Status.fromCode(reader.readByte());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user