mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-27 12:26:48 +01:00
Sony WH-1000XM5: Add power off, fix battery, fix speak-to-chat fetch
This commit is contained in:
parent
7b3fbeb4af
commit
e0d481bb36
@ -48,7 +48,7 @@ public class SonyWH1000XM5Coordinator extends SonyHeadphonesCoordinator {
|
||||
// TODO R.xml.devicesettings_connect_two_devices,
|
||||
// TODO automatic ANC depending on state (might need phone?)
|
||||
SonyHeadphonesCapabilities.BatterySingle,
|
||||
// TODO SonyHeadphonesCapabilities.PowerOffFromPhone,
|
||||
SonyHeadphonesCapabilities.PowerOffFromPhone,
|
||||
SonyHeadphonesCapabilities.AmbientSoundControl,
|
||||
SonyHeadphonesCapabilities.SpeakToChatEnabled,
|
||||
SonyHeadphonesCapabilities.SpeakToChatConfig,
|
||||
|
@ -25,6 +25,7 @@ public enum PayloadTypeV2 {
|
||||
|
||||
BATTERY_LEVEL_REQUEST(MessageType.COMMAND_1, 0x22),
|
||||
BATTERY_LEVEL_REPLY(MessageType.COMMAND_1, 0x23),
|
||||
POWER_SET(MessageType.COMMAND_1, 0x24),
|
||||
BATTERY_LEVEL_NOTIFY(MessageType.COMMAND_1, 0x25),
|
||||
|
||||
AUTOMATIC_POWER_OFF_GET(MessageType.COMMAND_1, 0x26),
|
||||
|
@ -365,8 +365,14 @@ public class SonyProtocolImplV2 extends SonyProtocolImplV1 {
|
||||
|
||||
@Override
|
||||
public Request powerOff() {
|
||||
LOG.warn("Power off not implemented for V2");
|
||||
return null;
|
||||
return new Request(
|
||||
PayloadTypeV2.POWER_SET.getMessageType(),
|
||||
new byte[]{
|
||||
PayloadTypeV2.POWER_SET.getCode(),
|
||||
(byte) 0x03,
|
||||
(byte) 0x01
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -661,6 +667,8 @@ public class SonyProtocolImplV2 extends SonyProtocolImplV1 {
|
||||
@Override
|
||||
protected BatteryType decodeBatteryType(final byte b) {
|
||||
switch (b) {
|
||||
case 0x00:
|
||||
return BatteryType.SINGLE;
|
||||
case 0x09:
|
||||
return BatteryType.DUAL;
|
||||
case 0x0a:
|
||||
@ -673,10 +681,11 @@ public class SonyProtocolImplV2 extends SonyProtocolImplV1 {
|
||||
@Override
|
||||
protected byte encodeBatteryType(final BatteryType batteryType) {
|
||||
switch (batteryType) {
|
||||
case SINGLE:
|
||||
return 0x00;
|
||||
case DUAL:
|
||||
return 0x09;
|
||||
case CASE:
|
||||
case SINGLE: // TODO: This is not the code for single, but we need to encode something
|
||||
return 0x0a;
|
||||
}
|
||||
|
||||
|
@ -19,11 +19,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.pro
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.MessageType;
|
||||
|
||||
public enum PayloadTypeV3 {
|
||||
QUICK_ACCESS_GET(MessageType.COMMAND_1, 0xf6),
|
||||
QUICK_ACCESS_RET(MessageType.COMMAND_1, 0xf7),
|
||||
QUICK_ACCESS_SET(MessageType.COMMAND_1, 0xf8),
|
||||
QUICK_ACCESS_NOTIFY(MessageType.COMMAND_1, 0xf9),
|
||||
|
||||
AMBIENT_SOUND_CONTROL_BUTTON_MODE_GET(MessageType.COMMAND_1, 0xfa),
|
||||
AMBIENT_SOUND_CONTROL_BUTTON_MODE_RET(MessageType.COMMAND_1, 0xfb),
|
||||
AMBIENT_SOUND_CONTROL_BUTTON_MODE_SET(MessageType.COMMAND_1, 0xfc),
|
||||
|
@ -135,9 +135,9 @@ public class SonyProtocolImplV3 extends SonyProtocolImplV2 {
|
||||
@Override
|
||||
public Request getQuickAccess() {
|
||||
return new Request(
|
||||
PayloadTypeV3.QUICK_ACCESS_GET.getMessageType(),
|
||||
PayloadTypeV1.AUTOMATIC_POWER_OFF_BUTTON_MODE_GET.getMessageType(),
|
||||
new byte[]{
|
||||
PayloadTypeV3.QUICK_ACCESS_GET.getCode(),
|
||||
PayloadTypeV1.AUTOMATIC_POWER_OFF_BUTTON_MODE_GET.getCode(),
|
||||
(byte) 0x0d
|
||||
}
|
||||
);
|
||||
@ -146,9 +146,9 @@ public class SonyProtocolImplV3 extends SonyProtocolImplV2 {
|
||||
@Override
|
||||
public Request setQuickAccess(final QuickAccess quickAccess) {
|
||||
return new Request(
|
||||
PayloadTypeV3.QUICK_ACCESS_SET.getMessageType(),
|
||||
PayloadTypeV1.AUTOMATIC_POWER_OFF_BUTTON_MODE_SET.getMessageType(),
|
||||
new byte[]{
|
||||
PayloadTypeV3.QUICK_ACCESS_SET.getCode(),
|
||||
PayloadTypeV1.AUTOMATIC_POWER_OFF_BUTTON_MODE_SET.getCode(),
|
||||
(byte) 0x0d,
|
||||
(byte) 0x02,
|
||||
quickAccess.getModeDoubleTap().getCode(),
|
||||
@ -232,9 +232,6 @@ public class SonyProtocolImplV3 extends SonyProtocolImplV2 {
|
||||
final PayloadTypeV3 payloadType = PayloadTypeV3.fromCode(messageType, payload[0]);
|
||||
|
||||
switch (payloadType) {
|
||||
case QUICK_ACCESS_RET:
|
||||
case QUICK_ACCESS_NOTIFY:
|
||||
return handleQuickAccess(payload);
|
||||
case AMBIENT_SOUND_CONTROL_BUTTON_MODE_RET:
|
||||
case AMBIENT_SOUND_CONTROL_BUTTON_MODE_NOTIFY:
|
||||
return handleAmbientSoundControlButtonMode(payload);
|
||||
@ -350,6 +347,43 @@ public class SonyProtocolImplV3 extends SonyProtocolImplV2 {
|
||||
return Collections.singletonList(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends GBDeviceEvent> handleSpeakToChatEnabled(final byte[] payload) {
|
||||
if (payload.length != 4) {
|
||||
LOG.warn("Unexpected payload length {}", payload.length);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (payload[1] != 0x0c) {
|
||||
LOG.warn("Not speak to chat enabled, ignoring");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Boolean disabled = booleanFromByte(payload[3]);
|
||||
if (disabled == null) {
|
||||
LOG.warn("Unknown speak to chat enabled code {}", String.format("%02x", payload[3]));
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
LOG.debug("Speak to chat: {}", !disabled);
|
||||
|
||||
final GBDeviceEventUpdatePreferences event = new GBDeviceEventUpdatePreferences()
|
||||
.withPreferences(new SpeakToChatEnabled(!disabled).toPreferences());
|
||||
|
||||
return Collections.singletonList(event);
|
||||
}
|
||||
|
||||
public List<? extends GBDeviceEvent> handleAutomaticPowerOffButtonMode(final byte[] payload) {
|
||||
switch (payload[1]) {
|
||||
case 0x0c:
|
||||
return handleSpeakToChatEnabled(payload);
|
||||
case 0x0d:
|
||||
return handleQuickAccess(payload);
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public List<? extends GBDeviceEvent> handleVoiceNotifications(final byte[] payload) {
|
||||
if (payload.length != 4) {
|
||||
LOG.warn("Unexpected payload length {}", payload.length);
|
||||
|
@ -46,6 +46,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SpeakT
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.VoiceNotifications;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.Request;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.MockSonyCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.v1.params.BatteryType;
|
||||
|
||||
public class SonyProtocolImplV3Test {
|
||||
private final MockSonyCoordinator coordinator = new MockSonyCoordinator();
|
||||
@ -98,6 +99,20 @@ public class SonyProtocolImplV3Test {
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBattery() {
|
||||
final Map<BatteryType, String> commands = new LinkedHashMap<BatteryType, String>() {{
|
||||
put(BatteryType.SINGLE, "22:00");
|
||||
put(BatteryType.DUAL, "22:09");
|
||||
put(BatteryType.CASE, "22:0a");
|
||||
}};
|
||||
|
||||
for (Map.Entry<BatteryType, String> entry : commands.entrySet()) {
|
||||
final Request request = protocol.getBattery(entry.getKey());
|
||||
assertRequest(request, 0x0c, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getQuickAccess() {
|
||||
final Request request = protocol.getQuickAccess();
|
||||
@ -175,6 +190,12 @@ public class SonyProtocolImplV3Test {
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void powerOff() {
|
||||
final Request request = protocol.powerOff();
|
||||
assertRequest(request, 0x0c, "24:03:01");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleQuickAccess() {
|
||||
final Map<String, QuickAccess> commands = new LinkedHashMap<String, QuickAccess>() {{
|
||||
|
Loading…
Reference in New Issue
Block a user