From 2b4493eeb71336447200621164f35a1ba53c7959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Wed, 4 Dec 2024 18:50:44 +0000 Subject: [PATCH] Oppo Headphones: Fix decoding of concatenated responses --- .../devices/oppo/OppoHeadphonesProtocol.java | 33 ++++++++++--------- .../oppo/OppoHeadphonesProtocolTest.java | 13 ++++++++ 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesProtocol.java index acbf84ae7..304ec6be4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesProtocol.java @@ -42,7 +42,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.oppo.commands.TouchC import nodomain.freeyourgadget.gadgetbridge.service.devices.oppo.commands.TouchConfigType; import nodomain.freeyourgadget.gadgetbridge.service.devices.oppo.commands.TouchConfigValue; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; -import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs; public class OppoHeadphonesProtocol extends GBDeviceProtocol { @@ -59,24 +58,26 @@ public class OppoHeadphonesProtocol extends GBDeviceProtocol { @Override public GBDeviceEvent[] decodeResponse(final byte[] responseData) { final List events = new ArrayList<>(); - int i = 0; - while (i < responseData.length) { - if (responseData[i] != CMD_PREAMBLE) { - LOG.warn("Unexpected preamble {}", responseData[i]); - i++; + final ByteBuffer buf = ByteBuffer.wrap(responseData); + + while (buf.position() < buf.limit()) { + final byte preamble = buf.get(); + if (preamble != CMD_PREAMBLE) { + LOG.warn("Unexpected preamble {}", preamble); continue; } - final int totalLength = responseData[i + 1] & 0xff; - if (responseData.length - i < totalLength + 2) { - LOG.error("Got partial response with {} bytes, expected {}", responseData.length - i, totalLength + 2); + + final int totalLength = buf.get() & 0xff; + if (buf.limit() - buf.position() < totalLength) { + LOG.error("Got partial response with {} bytes, expected {}", buf.limit() - buf.position(), totalLength); break; } - final byte[] singleResponse = ArrayUtils.subarray(responseData, i, i + totalLength + 3); + final byte[] singleResponse = new byte[totalLength + 2]; + buf.position(buf.position() - 2); + buf.get(singleResponse); events.addAll(handleSingleResponse(singleResponse)); - - i += totalLength + 2; } return events.toArray(new GBDeviceEvent[0]); } @@ -92,7 +93,7 @@ public class OppoHeadphonesProtocol extends GBDeviceProtocol { return Collections.emptyList(); } - final byte totalLength = responseBuf.get(); + final int totalLength = responseBuf.get() & 0xff; if (responseData.length != totalLength + 2) { LOG.error("Invalid number of bytes {}, expected {}", responseData.length, totalLength + 2); return Collections.emptyList(); @@ -235,15 +236,15 @@ public class OppoHeadphonesProtocol extends GBDeviceProtocol { final TouchConfigValue value = TouchConfigValue.fromCode(valueCode); if (side == null) { - LOG.warn("Unknown side code {}", sideCode); + LOG.warn("Unknown touch side code {}", sideCode); continue; } if (type == null) { - LOG.warn("Unknown type code {}", typeCode); + LOG.warn("Unknown touch type code {}", typeCode); continue; } if (value == null) { - LOG.warn("Unknown value code {}", valueCode); + LOG.warn("Unknown touch value code {}", valueCode); continue; } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesProtocolTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesProtocolTest.java index 65b5b5dbd..cebbab568 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesProtocolTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/oppo/OppoHeadphonesProtocolTest.java @@ -4,6 +4,8 @@ import org.junit.Assert; import org.junit.Test; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.test.TestBase; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -28,4 +30,15 @@ public class OppoHeadphonesProtocolTest extends TestBase { GBDeviceEventVersionInfo realmeEvent = (GBDeviceEventVersionInfo) realme[0]; Assert.assertEquals("1.1.0.75", realmeEvent.fwVersion); } + + @Test + public void testMultipleResponses() { + final OppoHeadphonesProtocol protocol = new OppoHeadphonesProtocol(null); + GBDeviceEvent[] events = protocol.decodeResponse(GB.hexStringToByteArray("AA4100000881013A00000E010100000101010101010205010103000101040C0101050001010600020100000201010102010206020103000201040B0201050002010600AA0F000006810208000003016402640346")); + Assert.assertEquals(4, events.length); + Assert.assertTrue(events[0] instanceof GBDeviceEventUpdatePreferences); + Assert.assertTrue(events[1] instanceof GBDeviceEventBatteryInfo); + Assert.assertTrue(events[2] instanceof GBDeviceEventBatteryInfo); + Assert.assertTrue(events[3] instanceof GBDeviceEventBatteryInfo); + } }