mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-01 06:22:55 +01:00
Use SoundcorePacket for Liberty 3 Pro
This commit is contained in:
parent
c06e22b85e
commit
69441a6a79
@ -8,10 +8,8 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -21,6 +19,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInf
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.AmbientSoundControlButtonMode;
|
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.AmbientSoundControlButtonMode;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.soundcore.SoundcorePacket;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
@ -59,36 +58,34 @@ public class SoundcoreLibertyProtocol extends GBDeviceProtocol {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public GBDeviceEvent[] decodeResponse(byte[] responseData) {
|
public GBDeviceEvent[] decodeResponse(byte[] responseData) {
|
||||||
// Byte 0-4: Header
|
ByteBuffer buf = ByteBuffer.wrap(responseData);
|
||||||
// Byte 5-6: Command (Audio-Mode)
|
SoundcorePacket packet = SoundcorePacket.decode(buf);
|
||||||
// Byte 7: Size of data
|
|
||||||
// Byte 8-(x-1): Data
|
if (packet == null)
|
||||||
// Byte x: Checksum
|
return null;
|
||||||
if (responseData.length == 0) return null;
|
|
||||||
|
|
||||||
List<GBDeviceEvent> devEvts = new ArrayList<>();
|
List<GBDeviceEvent> devEvts = new ArrayList<>();
|
||||||
|
short cmd = packet.getCommand();
|
||||||
|
byte[] payload = packet.getPayload();
|
||||||
|
|
||||||
byte[] command = Arrays.copyOfRange(responseData, 5, 7);
|
if (cmd == (short) 0x0101) {
|
||||||
byte[] data = Arrays.copyOfRange(responseData, 8, responseData.length-1);
|
|
||||||
|
|
||||||
if (Arrays.equals(command, new byte[]{0x01, 0x01})) {
|
|
||||||
// a lot of other data is in here, anything interesting?
|
// a lot of other data is in here, anything interesting?
|
||||||
String firmware1 = readString(data, 7, 5);
|
String firmware1 = readString(payload, 6, 5);
|
||||||
String firmware2 = readString(data, 12, 5);
|
String firmware2 = readString(payload, 11, 5);
|
||||||
String serialNumber = readString(data, 17, 16);
|
String serialNumber = readString(payload, 16, 16);
|
||||||
devEvts.add(buildVersionInfo(firmware1, firmware2, serialNumber));
|
devEvts.add(buildVersionInfo(firmware1, firmware2, serialNumber));
|
||||||
} else if (Arrays.equals(command, new byte[]{0x01, (byte) 0x8d})) {
|
} else if (cmd == (short) 0x8d01) {
|
||||||
LOG.debug("Unknown incoming message - command: " + hexdump(command) + ", dump: " + hexdump(responseData));
|
LOG.debug("Unknown incoming message - command: " + cmd + ", dump: " + hexdump(responseData));
|
||||||
} else if (Arrays.equals(command, new byte[]{0x05, (byte) 0x82})) {
|
} else if (cmd == (short) 0x8205) {
|
||||||
LOG.debug("Unknown incoming message - command: " + hexdump(command) + ", dump: " + hexdump(responseData));
|
LOG.debug("Unknown incoming message - command: " + cmd + ", dump: " + hexdump(responseData));
|
||||||
} else if (Arrays.equals(command, new byte[]{0x05, 0x01})) {
|
} else if (cmd == (short) 0x0105) {
|
||||||
LOG.debug("Unknown incoming message - command: " + hexdump(command) + ", dump: " + hexdump(responseData));
|
LOG.debug("Unknown incoming message - command: " + cmd + ", dump: " + hexdump(responseData));
|
||||||
} else if (Arrays.equals(command, new byte[]{0x06, 0x01})) { //Sound Mode Update
|
} else if (cmd == (short) 0x0106) { //Sound Mode Update
|
||||||
decodeAudioMode(data);
|
decodeAudioMode(payload);
|
||||||
} else if (Arrays.equals(command, new byte[]{0x01, 0x03})) { // Battery Update
|
} else if (cmd == (short) 0x0301) { // Battery Update
|
||||||
int batteryLeft = data[1] * 20;
|
int batteryLeft = payload[0] * 20;
|
||||||
int batteryRight = data[2] * 20;
|
int batteryRight = payload[1] * 20;
|
||||||
int batteryCase = data[3] * 20;
|
int batteryCase = payload[2] * 20;
|
||||||
|
|
||||||
devEvts.add(buildBatteryInfo(battery_case, batteryCase));
|
devEvts.add(buildBatteryInfo(battery_case, batteryCase));
|
||||||
devEvts.add(buildBatteryInfo(battery_earphone_left, batteryLeft));
|
devEvts.add(buildBatteryInfo(battery_earphone_left, batteryLeft));
|
||||||
@ -96,7 +93,7 @@ public class SoundcoreLibertyProtocol extends GBDeviceProtocol {
|
|||||||
} else {
|
} else {
|
||||||
// see https://github.com/gmallios/SoundcoreManager/blob/master/soundcore-lib/src/models/packet_kind.rs
|
// see https://github.com/gmallios/SoundcoreManager/blob/master/soundcore-lib/src/models/packet_kind.rs
|
||||||
// for a mapping for other soundcore devices (similar protocol?)
|
// for a mapping for other soundcore devices (similar protocol?)
|
||||||
LOG.debug("Unknown incoming message - command: " + hexdump(command) + ", dump: " + hexdump(responseData));
|
LOG.debug("Unknown incoming message - command: " + cmd + ", dump: " + hexdump(responseData));
|
||||||
}
|
}
|
||||||
return devEvts.toArray(new GBDeviceEvent[devEvts.size()]);
|
return devEvts.toArray(new GBDeviceEvent[devEvts.size()]);
|
||||||
}
|
}
|
||||||
@ -107,25 +104,25 @@ public class SoundcoreLibertyProtocol extends GBDeviceProtocol {
|
|||||||
String soundmode = "off";
|
String soundmode = "off";
|
||||||
int anc_strength = 0;
|
int anc_strength = 0;
|
||||||
|
|
||||||
if (payload[1] == 0x00) {
|
if (payload[0] == 0x00) {
|
||||||
soundmode = "noise_cancelling";
|
soundmode = "noise_cancelling";
|
||||||
} else if (payload[1] == 0x01) {
|
} else if (payload[0] == 0x01) {
|
||||||
soundmode = "ambient_sound";
|
soundmode = "ambient_sound";
|
||||||
} else if (payload[1] == 0x02) {
|
} else if (payload[0] == 0x02) {
|
||||||
soundmode = "off";
|
soundmode = "off";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload[2] == 0x10) {
|
if (payload[1] == 0x10) {
|
||||||
anc_strength = 0;
|
anc_strength = 0;
|
||||||
} else if (payload[2] == 0x20) {
|
} else if (payload[1] == 0x20) {
|
||||||
anc_strength = 1;
|
anc_strength = 1;
|
||||||
} else if (payload[2] == 0x30) {
|
} else if (payload[1] == 0x30) {
|
||||||
anc_strength = 2;
|
anc_strength = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean vocal_mode = (payload[3] == 0x01);
|
boolean vocal_mode = (payload[2] == 0x01);
|
||||||
boolean adaptive_anc = (payload[4] == 0x01);
|
boolean adaptive_anc = (payload[3] == 0x01);
|
||||||
boolean windnoiseReduction = (payload[5] == 0x01);
|
boolean windnoiseReduction = (payload[4] == 0x01);
|
||||||
|
|
||||||
editor.putString(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_AMBIENT_SOUND_CONTROL, soundmode);
|
editor.putString(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_AMBIENT_SOUND_CONTROL, soundmode);
|
||||||
editor.putInt(DeviceSettingsPreferenceConst.PREF_SONY_AMBIENT_SOUND_LEVEL, anc_strength);
|
editor.putInt(DeviceSettingsPreferenceConst.PREF_SONY_AMBIENT_SOUND_LEVEL, anc_strength);
|
||||||
@ -200,13 +197,13 @@ public class SoundcoreLibertyProtocol extends GBDeviceProtocol {
|
|||||||
// Miscellaneous Settings
|
// Miscellaneous Settings
|
||||||
case DeviceSettingsPreferenceConst.PREF_SOUNDCORE_WEARING_DETECTION:
|
case DeviceSettingsPreferenceConst.PREF_SOUNDCORE_WEARING_DETECTION:
|
||||||
boolean wearingDetection = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_WEARING_DETECTION, false);
|
boolean wearingDetection = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_WEARING_DETECTION, false);
|
||||||
return encodeMessage((byte) 0x01, (byte) 0x81, new byte[]{0x00, encodeBoolean(wearingDetection)});
|
return new SoundcorePacket((short) 0x8101, new byte[]{encodeBoolean(wearingDetection)}).encode();
|
||||||
case DeviceSettingsPreferenceConst.PREF_SOUNDCORE_WEARING_TONE:
|
case DeviceSettingsPreferenceConst.PREF_SOUNDCORE_WEARING_TONE:
|
||||||
boolean wearingTone = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_WEARING_TONE, false);
|
boolean wearingTone = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_WEARING_TONE, false);
|
||||||
return encodeMessage((byte) 0x01, (byte) 0x8c, new byte[]{0x00, encodeBoolean(wearingTone)});
|
return new SoundcorePacket((short) 0x8c01, new byte[]{encodeBoolean(wearingTone)}).encode();
|
||||||
case DeviceSettingsPreferenceConst.PREF_SOUNDCORE_TOUCH_TONE:
|
case DeviceSettingsPreferenceConst.PREF_SOUNDCORE_TOUCH_TONE:
|
||||||
boolean touchTone = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_TOUCH_TONE, false);
|
boolean touchTone = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_TOUCH_TONE, false);
|
||||||
return encodeMessage((byte) 0x01, (byte) 0x83, new byte[]{0x00, encodeBoolean(touchTone)});
|
return new SoundcorePacket((short) 0x8301, new byte[]{encodeBoolean(touchTone)}).encode();
|
||||||
default:
|
default:
|
||||||
LOG.debug("Unsupported CONFIG: " + config);
|
LOG.debug("Unsupported CONFIG: " + config);
|
||||||
}
|
}
|
||||||
@ -215,21 +212,19 @@ public class SoundcoreLibertyProtocol extends GBDeviceProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
byte[] encodeDeviceInfoRequest() {
|
byte[] encodeDeviceInfoRequest() {
|
||||||
byte[] payload = new byte[]{0x00};
|
return new SoundcorePacket((short) 0x0101).encode();
|
||||||
return encodeMessage((byte) 0x01, (byte) 0x01, payload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] encodeMysteryDataRequest1() {
|
byte[] encodeMysteryDataRequest1() {
|
||||||
byte[] payload = new byte[]{0x00, 0x00};
|
byte[] payload = new byte[]{0x00};
|
||||||
return encodeMessage((byte) 0x01, (byte) 0x8d, payload);
|
return new SoundcorePacket((short) 0x8d01, payload).encode();
|
||||||
}
|
}
|
||||||
byte[] encodeMysteryDataRequest2() {
|
byte[] encodeMysteryDataRequest2() {
|
||||||
byte[] payload = new byte[]{0x00};
|
return new SoundcorePacket((short) 0x0105).encode();
|
||||||
return encodeMessage((byte) 0x05, (byte) 0x01, payload);
|
|
||||||
}
|
}
|
||||||
byte[] encodeMysteryDataRequest3() {
|
byte[] encodeMysteryDataRequest3() {
|
||||||
byte[] payload = new byte[]{0x00, 0x00};
|
byte[] payload = new byte[]{0x00};
|
||||||
return encodeMessage((byte) 0x05, (byte) 0x82, payload);
|
return new SoundcorePacket((short) 0x8205, payload).encode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -280,8 +275,8 @@ public class SoundcoreLibertyProtocol extends GBDeviceProtocol {
|
|||||||
byte vocal_mode = encodeBoolean(prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_TRANSPARENCY_VOCAL_MODE, false));
|
byte vocal_mode = encodeBoolean(prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_TRANSPARENCY_VOCAL_MODE, false));
|
||||||
byte windnoise_reduction = encodeBoolean(prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_WIND_NOISE_REDUCTION, false));
|
byte windnoise_reduction = encodeBoolean(prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_WIND_NOISE_REDUCTION, false));
|
||||||
|
|
||||||
byte[] payload = new byte[]{0x00, anc_mode, anc_strength, vocal_mode, adaptive_anc, windnoise_reduction, 0x01};
|
byte[] payload = new byte[]{anc_mode, anc_strength, vocal_mode, adaptive_anc, windnoise_reduction, 0x01};
|
||||||
return encodeMessage((byte) 0x06, (byte) 0x81, payload);
|
return new SoundcorePacket((short) 0x8106, payload).encode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -307,8 +302,8 @@ public class SoundcoreLibertyProtocol extends GBDeviceProtocol {
|
|||||||
LOG.error("Invalid Tap action");
|
LOG.error("Invalid Tap action");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
payload = new byte[]{0x00, 0x00, action.getCode(), enabled_byte};
|
payload = new byte[]{0x00, action.getCode(), enabled_byte};
|
||||||
return encodeMessage((byte) 0x04, (byte) 0x83, payload);
|
return new SoundcorePacket((short) 0x8304, payload).encode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -335,8 +330,8 @@ public class SoundcoreLibertyProtocol extends GBDeviceProtocol {
|
|||||||
LOG.error("Invalid Tap action");
|
LOG.error("Invalid Tap action");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
byte[] payload = new byte[] {0x00, encodeBoolean(right), action.getCode(), function_byte};
|
byte[] payload = new byte[] {encodeBoolean(right), action.getCode(), function_byte};
|
||||||
return encodeMessage((byte) 0x04, (byte) 0x81, payload);
|
return new SoundcorePacket((short) 0x8104, payload).encode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -346,32 +341,11 @@ public class SoundcoreLibertyProtocol extends GBDeviceProtocol {
|
|||||||
private byte[] encodeControlAmbientModeMessage(boolean anc, boolean transparency, boolean normal) {
|
private byte[] encodeControlAmbientModeMessage(boolean anc, boolean transparency, boolean normal) {
|
||||||
// Original app does not allow only one true flag. Unsure if Earbuds accept this state.
|
// Original app does not allow only one true flag. Unsure if Earbuds accept this state.
|
||||||
byte ambientModes = (byte) (4 * (normal?1:0) + 2 * (transparency?1:0) + (anc?1:0));
|
byte ambientModes = (byte) (4 * (normal?1:0) + 2 * (transparency?1:0) + (anc?1:0));
|
||||||
return encodeMessage((byte) 0x06, (byte) 0x82, new byte[] {0x00, ambientModes});
|
return new SoundcorePacket((short) 0x8206, new byte[] {ambientModes}).encode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte encodeBoolean(boolean bool) {
|
private byte encodeBoolean(boolean bool) {
|
||||||
if (bool) return 0x01;
|
if (bool) return 0x01;
|
||||||
else return 0x00;
|
else return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] encodeMessage(byte command1, byte command2, byte[] payload) {
|
|
||||||
int size = 8 + payload.length + 1;
|
|
||||||
ByteBuffer msgBuf = ByteBuffer.allocate(size);
|
|
||||||
msgBuf.order(ByteOrder.BIG_ENDIAN);
|
|
||||||
msgBuf.put(new byte[] {0x08, (byte) 0xee, 0x00, 0x00, 0x00}); // header
|
|
||||||
msgBuf.put(command1);
|
|
||||||
msgBuf.put(command2);
|
|
||||||
msgBuf.put((byte) size);
|
|
||||||
|
|
||||||
msgBuf.put(payload);
|
|
||||||
|
|
||||||
byte checksum = -10;
|
|
||||||
checksum += command1 + command2 + size;
|
|
||||||
for (int b : payload) {
|
|
||||||
checksum += b;
|
|
||||||
}
|
|
||||||
msgBuf.put(checksum);
|
|
||||||
|
|
||||||
return msgBuf.array();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user