Oppo Headphones: Fix decoding of concatenated responses

This commit is contained in:
José Rebelo 2024-12-04 18:50:44 +00:00
parent 12671fb1e0
commit 2b4493eeb7
2 changed files with 30 additions and 16 deletions

View File

@ -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.TouchConfigType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.oppo.commands.TouchConfigValue; import nodomain.freeyourgadget.gadgetbridge.service.devices.oppo.commands.TouchConfigValue;
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs; import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs;
public class OppoHeadphonesProtocol extends GBDeviceProtocol { public class OppoHeadphonesProtocol extends GBDeviceProtocol {
@ -59,24 +58,26 @@ public class OppoHeadphonesProtocol extends GBDeviceProtocol {
@Override @Override
public GBDeviceEvent[] decodeResponse(final byte[] responseData) { public GBDeviceEvent[] decodeResponse(final byte[] responseData) {
final List<GBDeviceEvent> events = new ArrayList<>(); final List<GBDeviceEvent> events = new ArrayList<>();
int i = 0; final ByteBuffer buf = ByteBuffer.wrap(responseData);
while (i < responseData.length) {
if (responseData[i] != CMD_PREAMBLE) { while (buf.position() < buf.limit()) {
LOG.warn("Unexpected preamble {}", responseData[i]); final byte preamble = buf.get();
i++; if (preamble != CMD_PREAMBLE) {
LOG.warn("Unexpected preamble {}", preamble);
continue; continue;
} }
final int totalLength = responseData[i + 1] & 0xff;
if (responseData.length - i < totalLength + 2) { final int totalLength = buf.get() & 0xff;
LOG.error("Got partial response with {} bytes, expected {}", responseData.length - i, totalLength + 2); if (buf.limit() - buf.position() < totalLength) {
LOG.error("Got partial response with {} bytes, expected {}", buf.limit() - buf.position(), totalLength);
break; 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)); events.addAll(handleSingleResponse(singleResponse));
i += totalLength + 2;
} }
return events.toArray(new GBDeviceEvent[0]); return events.toArray(new GBDeviceEvent[0]);
} }
@ -92,7 +93,7 @@ public class OppoHeadphonesProtocol extends GBDeviceProtocol {
return Collections.emptyList(); return Collections.emptyList();
} }
final byte totalLength = responseBuf.get(); final int totalLength = responseBuf.get() & 0xff;
if (responseData.length != totalLength + 2) { if (responseData.length != totalLength + 2) {
LOG.error("Invalid number of bytes {}, expected {}", responseData.length, totalLength + 2); LOG.error("Invalid number of bytes {}, expected {}", responseData.length, totalLength + 2);
return Collections.emptyList(); return Collections.emptyList();
@ -235,15 +236,15 @@ public class OppoHeadphonesProtocol extends GBDeviceProtocol {
final TouchConfigValue value = TouchConfigValue.fromCode(valueCode); final TouchConfigValue value = TouchConfigValue.fromCode(valueCode);
if (side == null) { if (side == null) {
LOG.warn("Unknown side code {}", sideCode); LOG.warn("Unknown touch side code {}", sideCode);
continue; continue;
} }
if (type == null) { if (type == null) {
LOG.warn("Unknown type code {}", typeCode); LOG.warn("Unknown touch type code {}", typeCode);
continue; continue;
} }
if (value == null) { if (value == null) {
LOG.warn("Unknown value code {}", valueCode); LOG.warn("Unknown touch value code {}", valueCode);
continue; continue;
} }

View File

@ -4,6 +4,8 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; 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.deviceevents.GBDeviceEventVersionInfo;
import nodomain.freeyourgadget.gadgetbridge.test.TestBase; import nodomain.freeyourgadget.gadgetbridge.test.TestBase;
import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.GB;
@ -28,4 +30,15 @@ public class OppoHeadphonesProtocolTest extends TestBase {
GBDeviceEventVersionInfo realmeEvent = (GBDeviceEventVersionInfo) realme[0]; GBDeviceEventVersionInfo realmeEvent = (GBDeviceEventVersionInfo) realme[0];
Assert.assertEquals("1.1.0.75", realmeEvent.fwVersion); 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);
}
} }