mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Zepp OS: Allow upload of UIHH AGPS bundles
This commit is contained in:
Generated
+1
@@ -161,6 +161,7 @@
|
||||
<w>trofimov</w>
|
||||
<w>tysiak</w>
|
||||
<w>uart</w>
|
||||
<w>uihh</w>
|
||||
<w>uint</w>
|
||||
<w>utsob</w>
|
||||
<w>uuids</w>
|
||||
|
||||
+10
-5
@@ -28,6 +28,7 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||
@@ -45,6 +46,10 @@ public class UIHHContainer {
|
||||
return files;
|
||||
}
|
||||
|
||||
public List<FileType> getFileTypes() {
|
||||
return files.stream().map(FileEntry::getType).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public byte[] getFile(final FileType fileType) {
|
||||
for (final FileEntry file : files) {
|
||||
if (file.getType() == fileType) {
|
||||
@@ -91,8 +96,8 @@ public class UIHHContainer {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int crc32 = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, 12, 12 + 4));
|
||||
final int length = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, 22, 22 + 4));
|
||||
final int crc32 = BLETypeConversions.toUint32(bytes, 12);
|
||||
final int length = BLETypeConversions.toUint32(bytes, 22);
|
||||
|
||||
if (length + 32 != bytes.length) {
|
||||
LOG.error("Length mismatch between header and bytes: {}/{}", length, bytes.length);
|
||||
@@ -122,14 +127,14 @@ public class UIHHContainer {
|
||||
|
||||
final FileType type = FileType.fromValue(bytes[i]);
|
||||
if (type == null) {
|
||||
LOG.error("Unknown type byte {} at position {}", String.format("0x%x", bytes[i], i));
|
||||
LOG.error("Unknown type byte {} at position {}", String.format("0x%x", bytes[i]), i);
|
||||
return null;
|
||||
}
|
||||
i++;
|
||||
|
||||
final int fileLength = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, i, i + 4));
|
||||
final int fileLength = BLETypeConversions.toUint32(bytes, i);
|
||||
i += 4;
|
||||
final int fileCrc32 = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, i, i + 4));
|
||||
final int fileCrc32 = BLETypeConversions.toUint32(bytes, i);
|
||||
i += 4;
|
||||
|
||||
if (i + fileLength > bytes.length) {
|
||||
|
||||
+64
-16
@@ -21,6 +21,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.UIHHContainer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
|
||||
@@ -29,18 +31,22 @@ import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException;
|
||||
public class ZeppOsAgpsFile {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ZeppOsAgpsFile.class);
|
||||
|
||||
private final byte[] zipBytes;
|
||||
private final byte[] fileBytes;
|
||||
|
||||
public ZeppOsAgpsFile(final byte[] zipBytes) {
|
||||
this.zipBytes = zipBytes;
|
||||
public ZeppOsAgpsFile(final byte[] fileBytes) {
|
||||
this.fileBytes = fileBytes;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
if (!GBZipFile.isZipFile(zipBytes)) {
|
||||
return false;
|
||||
if (GBZipFile.isZipFile(fileBytes)) {
|
||||
return isValidAsEpoZip();
|
||||
} else {
|
||||
return isValidAsUihh();
|
||||
}
|
||||
}
|
||||
|
||||
final GBZipFile zipFile = new GBZipFile(zipBytes);
|
||||
private boolean isValidAsEpoZip() {
|
||||
final GBZipFile zipFile = new GBZipFile(fileBytes);
|
||||
|
||||
try {
|
||||
final byte[] manifestBin = zipFile.getFileFromZip("META-INF/MANIFEST.MF");
|
||||
@@ -61,22 +67,64 @@ public class ZeppOsAgpsFile {
|
||||
LOG.error("Failed to parse read MANIFEST or check file", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isValidAsUihh() {
|
||||
final UIHHContainer uihh = UIHHContainer.fromRawBytes(fileBytes);
|
||||
if (uihh == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final List<UIHHContainer.FileType> fileTypes = uihh.getFileTypes();
|
||||
final List<UIHHContainer.FileType> expectedFileTypes = Arrays.asList(
|
||||
UIHHContainer.FileType.GPS_ALM_BIN,
|
||||
UIHHContainer.FileType.GLN_ALM_BIN,
|
||||
UIHHContainer.FileType.LLE_BDS_LLE,
|
||||
UIHHContainer.FileType.LLE_GPS_LLE,
|
||||
UIHHContainer.FileType.LLE_GLO_LLE,
|
||||
UIHHContainer.FileType.LLE_GAL_LLE,
|
||||
UIHHContainer.FileType.LLE_QZSS_LLE
|
||||
);
|
||||
|
||||
if (fileTypes.size() != expectedFileTypes.size()) {
|
||||
LOG.warn("uihh file types mismatch - expected {}, found {}", expectedFileTypes.size(), fileTypes.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (final UIHHContainer.FileType fileType : expectedFileTypes) {
|
||||
if (!fileTypes.contains(fileType)) {
|
||||
LOG.warn("uihh is missing file type {}", fileType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] getUihhBytes() {
|
||||
final UIHHContainer uihh = new UIHHContainer();
|
||||
if (GBZipFile.isZipFile(fileBytes)) {
|
||||
// EPO zip - repackage into UIHH
|
||||
final UIHHContainer uihh = new UIHHContainer();
|
||||
|
||||
final GBZipFile zipFile = new GBZipFile(zipBytes);
|
||||
final GBZipFile zipFile = new GBZipFile(fileBytes);
|
||||
|
||||
try {
|
||||
uihh.addFile(UIHHContainer.FileType.AGPS_EPO_GR_3, zipFile.getFileFromZip("EPO_GR_3.DAT"));
|
||||
uihh.addFile(UIHHContainer.FileType.AGPS_EPO_GAL_7, zipFile.getFileFromZip("EPO_GAL_7.DAT"));
|
||||
uihh.addFile(UIHHContainer.FileType.AGPS_EPO_BDS_3, zipFile.getFileFromZip("EPO_BDS_3.DAT"));
|
||||
} catch (final ZipFileException e) {
|
||||
throw new IllegalStateException("Failed to read file from zip", e);
|
||||
try {
|
||||
uihh.addFile(UIHHContainer.FileType.AGPS_EPO_GR_3, zipFile.getFileFromZip("EPO_GR_3.DAT"));
|
||||
uihh.addFile(UIHHContainer.FileType.AGPS_EPO_GAL_7, zipFile.getFileFromZip("EPO_GAL_7.DAT"));
|
||||
uihh.addFile(UIHHContainer.FileType.AGPS_EPO_BDS_3, zipFile.getFileFromZip("EPO_BDS_3.DAT"));
|
||||
} catch (final ZipFileException e) {
|
||||
throw new IllegalStateException("Failed to read file from zip", e);
|
||||
}
|
||||
|
||||
return uihh.toRawBytes();
|
||||
} else {
|
||||
final UIHHContainer uihhContainer = UIHHContainer.fromRawBytes(fileBytes);
|
||||
if (uihhContainer != null) {
|
||||
return fileBytes;
|
||||
}
|
||||
}
|
||||
|
||||
return uihh.toRawBytes();
|
||||
throw new IllegalStateException("Unknown file bytes - this should never happen");
|
||||
}
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.test.TestBase;
|
||||
|
||||
public class UIHHContainerTest extends TestBase {
|
||||
@Test
|
||||
@Ignore("helper test for development, remove this while debugging")
|
||||
public void localTest() throws IOException {
|
||||
byte[] bytes = Files.readAllBytes(new File("/storage/downloads/uihh.bin").toPath());
|
||||
final UIHHContainer uihhContainer = UIHHContainer.fromRawBytes(bytes);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user