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

Garmin: Support file archival (deletion) on watch

Also add original timestamp to local cache filename as the file identifier are reused
Also fix imports of Test class
This commit is contained in:
Daniele Gobbetti 2024-04-18 17:26:40 +02:00
parent 5c57392b85
commit 42e44de1ac
6 changed files with 106 additions and 8 deletions

View File

@ -10,6 +10,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.DownloadRequestMessage; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.DownloadRequestMessage;
@ -319,7 +320,9 @@ public class FileTransferHandler implements MessageHandler {
} }
public String getFileName() { public String getFileName() {
return getFiletype().name() + "_" + getFileIndex() + (getFiletype().isFitFile() ? ".fit" : ""); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String dateString = dateFormat.format(fileDate);
return getFiletype().name() + "_" + getFileIndex() + "_" + dateString + (getFiletype().isFitFile() ? ".fit" : "");
} }
@NonNull @NonNull

View File

@ -103,6 +103,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),
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),
WEATHER_REQUEST(5014, WeatherMessage.class), WEATHER_REQUEST(5014, WeatherMessage.class),

View File

@ -0,0 +1,41 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages;
import org.apache.commons.lang3.EnumUtils;
import java.util.EnumSet;
public class SetFileFlagsMessage extends GFDIMessage {
private final int fileIndex;
private final FileFlags flags;
public SetFileFlagsMessage(int fileIndex, FileFlags flags) {
this.garminMessage = GarminMessage.SET_FILE_FLAG;
this.fileIndex = fileIndex;
this.flags = flags;
}
@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.writeShort(this.fileIndex);
writer.writeByte((int) EnumUtils.generateBitVector(FileFlags.class, this.flags));
return true;
}
public enum FileFlags {
UNK_00000001,
UNK_00000010,
UNK_00000100,
UNK_00001000,
ARCHIVE,
;
public static EnumSet<FileFlags> fromBitMask(final int code) {
return EnumUtils.processBitVector(FileFlags.class, code);
}
}
}

View File

@ -26,6 +26,8 @@ public abstract class GFDIStatusMessage extends GFDIMessage {
SupportedFileTypesStatusMessage supportedFileTypesStatusMessage = SupportedFileTypesStatusMessage.parseIncoming(reader, garminMessage); SupportedFileTypesStatusMessage supportedFileTypesStatusMessage = SupportedFileTypesStatusMessage.parseIncoming(reader, garminMessage);
LOG.info("{}", supportedFileTypesStatusMessage); LOG.info("{}", supportedFileTypesStatusMessage);
return supportedFileTypesStatusMessage; return supportedFileTypesStatusMessage;
} else if (GarminMessage.SET_FILE_FLAG.equals(originalGarminMessage)) {
return SetFileFlagsStatusMessage.parseIncoming(reader, garminMessage);
} else if (GarminMessage.FIT_DEFINITION.equals(originalGarminMessage)) { } else if (GarminMessage.FIT_DEFINITION.equals(originalGarminMessage)) {
return FitDefinitionStatusMessage.parseIncoming(reader, originalGarminMessage); return FitDefinitionStatusMessage.parseIncoming(reader, originalGarminMessage);
} else if (GarminMessage.FIT_DATA.equals(originalGarminMessage)) { } else if (GarminMessage.FIT_DATA.equals(originalGarminMessage)) {

View File

@ -0,0 +1,58 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status;
import java.util.EnumSet;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.SetFileFlagsMessage;
public class SetFileFlagsStatusMessage extends GFDIStatusMessage {
private final Status status;
private final FlagsStatus flagsStatus;
private final int fileIdentifier;
private final EnumSet<SetFileFlagsMessage.FileFlags> fileFlags;
public SetFileFlagsStatusMessage(GarminMessage garminMessage, Status status, FlagsStatus flagsStatus, int fileIdentifier, EnumSet<SetFileFlagsMessage.FileFlags> fileFlags) {
this.garminMessage = garminMessage;
this.status = status;
this.flagsStatus = flagsStatus;
this.fileIdentifier = fileIdentifier;
this.fileFlags = fileFlags;
}
public static SetFileFlagsStatusMessage parseIncoming(MessageReader reader, GarminMessage garminMessage) {
final Status status = Status.fromCode(reader.readByte());
if (!status.equals(Status.ACK)) {
return null;
}
final FlagsStatus flagsStatus = FlagsStatus.fromCode(reader.readByte());
final int originalFileIdentifier = reader.readShort() + 1; //TODO: check if always or only on archival
final EnumSet<SetFileFlagsMessage.FileFlags> fileFlags = SetFileFlagsMessage.FileFlags.fromBitMask(reader.readByte());
if (!FlagsStatus.APPLIED.equals(flagsStatus)) {
LOG.warn("Received {} / {} for file identifier {} and flags {} - message {}", status, flagsStatus, originalFileIdentifier, fileFlags, garminMessage);
} else {
LOG.info("Received {} / {} for file identifier {} and flags {} - message {}", status, flagsStatus, originalFileIdentifier, fileFlags, garminMessage);
}
return new SetFileFlagsStatusMessage(garminMessage, status, flagsStatus, originalFileIdentifier, fileFlags);
}
enum FlagsStatus {
APPLIED,
ERROR, //guessed
;
public static FlagsStatus fromCode(final int code) {
for (final FlagsStatus status : FlagsStatus.values()) {
if (status.ordinal() == code) {
return status;
}
}
throw new IllegalArgumentException("Unknown FlagsStatus code " + code);
}
}
}

View File

@ -2,27 +2,20 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.threeten.bp.Instant;
import org.threeten.bp.ZoneId;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.communicator.CobsCoDec; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.communicator.CobsCoDec;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitFile; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitFile;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.GlobalFITMessage; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.GlobalFITMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.LocalMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.ChecksumCalculator;
import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.GB;