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>trofimov</w>
|
||||||
<w>tysiak</w>
|
<w>tysiak</w>
|
||||||
<w>uart</w>
|
<w>uart</w>
|
||||||
|
<w>uihh</w>
|
||||||
<w>uint</w>
|
<w>uint</w>
|
||||||
<w>utsob</w>
|
<w>utsob</w>
|
||||||
<w>uuids</w>
|
<w>uuids</w>
|
||||||
|
|||||||
+10
-5
@@ -28,6 +28,7 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||||
@@ -45,6 +46,10 @@ public class UIHHContainer {
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<FileType> getFileTypes() {
|
||||||
|
return files.stream().map(FileEntry::getType).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] getFile(final FileType fileType) {
|
public byte[] getFile(final FileType fileType) {
|
||||||
for (final FileEntry file : files) {
|
for (final FileEntry file : files) {
|
||||||
if (file.getType() == fileType) {
|
if (file.getType() == fileType) {
|
||||||
@@ -91,8 +96,8 @@ public class UIHHContainer {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int crc32 = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, 12, 12 + 4));
|
final int crc32 = BLETypeConversions.toUint32(bytes, 12);
|
||||||
final int length = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, 22, 22 + 4));
|
final int length = BLETypeConversions.toUint32(bytes, 22);
|
||||||
|
|
||||||
if (length + 32 != bytes.length) {
|
if (length + 32 != bytes.length) {
|
||||||
LOG.error("Length mismatch between header and bytes: {}/{}", length, 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]);
|
final FileType type = FileType.fromValue(bytes[i]);
|
||||||
if (type == null) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
final int fileLength = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, i, i + 4));
|
final int fileLength = BLETypeConversions.toUint32(bytes, i);
|
||||||
i += 4;
|
i += 4;
|
||||||
final int fileCrc32 = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, i, i + 4));
|
final int fileCrc32 = BLETypeConversions.toUint32(bytes, i);
|
||||||
i += 4;
|
i += 4;
|
||||||
|
|
||||||
if (i + fileLength > bytes.length) {
|
if (i + fileLength > bytes.length) {
|
||||||
|
|||||||
+64
-16
@@ -21,6 +21,8 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
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.service.devices.huami.UIHHContainer;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
|
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
|
||||||
@@ -29,18 +31,22 @@ import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException;
|
|||||||
public class ZeppOsAgpsFile {
|
public class ZeppOsAgpsFile {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ZeppOsAgpsFile.class);
|
private static final Logger LOG = LoggerFactory.getLogger(ZeppOsAgpsFile.class);
|
||||||
|
|
||||||
private final byte[] zipBytes;
|
private final byte[] fileBytes;
|
||||||
|
|
||||||
public ZeppOsAgpsFile(final byte[] zipBytes) {
|
public ZeppOsAgpsFile(final byte[] fileBytes) {
|
||||||
this.zipBytes = zipBytes;
|
this.fileBytes = fileBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
if (!GBZipFile.isZipFile(zipBytes)) {
|
if (GBZipFile.isZipFile(fileBytes)) {
|
||||||
return false;
|
return isValidAsEpoZip();
|
||||||
|
} else {
|
||||||
|
return isValidAsUihh();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final GBZipFile zipFile = new GBZipFile(zipBytes);
|
private boolean isValidAsEpoZip() {
|
||||||
|
final GBZipFile zipFile = new GBZipFile(fileBytes);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final byte[] manifestBin = zipFile.getFileFromZip("META-INF/MANIFEST.MF");
|
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);
|
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() {
|
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 {
|
try {
|
||||||
uihh.addFile(UIHHContainer.FileType.AGPS_EPO_GR_3, zipFile.getFileFromZip("EPO_GR_3.DAT"));
|
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_GAL_7, zipFile.getFileFromZip("EPO_GAL_7.DAT"));
|
||||||
uihh.addFile(UIHHContainer.FileType.AGPS_EPO_BDS_3, zipFile.getFileFromZip("EPO_BDS_3.DAT"));
|
uihh.addFile(UIHHContainer.FileType.AGPS_EPO_BDS_3, zipFile.getFileFromZip("EPO_BDS_3.DAT"));
|
||||||
} catch (final ZipFileException e) {
|
} catch (final ZipFileException e) {
|
||||||
throw new IllegalStateException("Failed to read file from zip", 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