mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
Handle ear detection and microphone detection for dual pods better.
This commit is contained in:
@@ -5,10 +5,16 @@ import java.util.*
|
||||
fun Byte.toHex(): String = String.format("%02X", this)
|
||||
fun UByte.toHex(): String = this.toByte().toHex()
|
||||
|
||||
val Byte.upperNibble get() = (this.toInt() shr 4 and 0b1111).toByte()
|
||||
val Byte.lowerNibble get() = (this.toInt() and 0b1111).toByte()
|
||||
val UByte.upperNibble get() = (this.toInt() shr 4 and 0b1111).toUByte()
|
||||
val UByte.lowerNibble get() = (this.toInt() and 0b1111).toUByte()
|
||||
val Byte.upperNibble get() = (this.toInt() shr 4 and 0b1111).toShort()
|
||||
val Byte.lowerNibble get() = (this.toInt() and 0b1111).toShort()
|
||||
val UByte.upperNibble get() = (this.toInt() shr 4 and 0b1111).toUShort()
|
||||
val UByte.lowerNibble get() = (this.toInt() and 0b1111).toUShort()
|
||||
|
||||
fun Byte.isBitSet(pos: Int): Boolean = BitSet.valueOf(arrayOf(this).toByteArray()).get(pos)
|
||||
fun UByte.isBitSet(pos: Int): Boolean = this.toByte().isBitSet(pos)
|
||||
fun UByte.isBitSet(pos: Int): Boolean = this.toByte().isBitSet(pos)
|
||||
|
||||
fun Short.isBitSet(pos: Int): Boolean = this.toByte().isBitSet(pos)
|
||||
fun UShort.isBitSet(pos: Int): Boolean = this.toShort().isBitSet(pos)
|
||||
|
||||
fun UShort.toBinaryString(): String = Integer.toBinaryString(this.toInt()).padStart(4, '0')
|
||||
fun UByte.toBinaryString(): String = Integer.toBinaryString(this.toInt()).padStart(8, '0')
|
||||
|
||||
+7
-5
@@ -7,7 +7,6 @@ import eu.darken.capod.R
|
||||
import eu.darken.capod.common.lists.binding
|
||||
import eu.darken.capod.databinding.OverviewPodsAppleDualItemBinding
|
||||
import eu.darken.capod.pods.core.*
|
||||
import eu.darken.capod.pods.core.HasDualPods.Pod
|
||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
||||
import eu.darken.capod.pods.core.apple.DualApplePods.DeviceColor
|
||||
import eu.darken.capod.pods.core.apple.DualApplePods.LidState
|
||||
@@ -31,6 +30,9 @@ class DualApplePodsCardVH(parent: ViewGroup) :
|
||||
text = sb
|
||||
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
||||
else setTypeface(typeface, Typeface.NORMAL)
|
||||
if (item.showDebug) {
|
||||
append(" [${device.primaryPod.name}]")
|
||||
}
|
||||
}
|
||||
deviceIcon.setImageResource(device.iconRes)
|
||||
|
||||
@@ -49,8 +51,8 @@ class DualApplePodsCardVH(parent: ViewGroup) :
|
||||
podLeftChargingIcon.isInvisible = !isLeftPodCharging
|
||||
podLeftChargingLabel.isInvisible = !isLeftPodCharging
|
||||
|
||||
podLeftMicrophoneIcon.isInvisible = microPhonePod != Pod.LEFT
|
||||
podLeftMicrophoneLabel.isInvisible = microPhonePod != Pod.LEFT
|
||||
podLeftMicrophoneIcon.isInvisible = !isLeftPodMicrophone
|
||||
podLeftMicrophoneLabel.isInvisible = !isLeftPodMicrophone
|
||||
|
||||
podLeftWearIcon.isInvisible = !isLeftPodInEar
|
||||
podLeftWearLabel.isInvisible = !isLeftPodInEar
|
||||
@@ -64,8 +66,8 @@ class DualApplePodsCardVH(parent: ViewGroup) :
|
||||
podRightChargingIcon.isInvisible = !isRightPodCharging
|
||||
podRightChargingLabel.isInvisible = !isRightPodCharging
|
||||
|
||||
podRightMicrophoneIcon.isInvisible = microPhonePod != Pod.RIGHT
|
||||
podRightMicrophoneLabel.isInvisible = microPhonePod != Pod.RIGHT
|
||||
podRightMicrophoneIcon.isInvisible = !isRightPodMicrophone
|
||||
podRightMicrophoneLabel.isInvisible = !isRightPodMicrophone
|
||||
|
||||
podRightWearIcon.isInvisible = !isRightPodInEar
|
||||
podRightWearLabel.isInvisible = !isRightPodInEar
|
||||
|
||||
@@ -6,6 +6,9 @@ import eu.darken.capod.common.debug.logging.Logging.Priority.*
|
||||
import eu.darken.capod.common.debug.logging.asLog
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.lowerNibble
|
||||
import eu.darken.capod.common.toBinaryString
|
||||
import eu.darken.capod.common.upperNibble
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.airpods.*
|
||||
import eu.darken.capod.pods.core.apple.beats.*
|
||||
@@ -63,6 +66,14 @@ class AppleFactory @Inject constructor(
|
||||
scanResult = scanResult,
|
||||
proximityMessage = pm,
|
||||
)
|
||||
if (device is DualApplePods) {
|
||||
device.apply {
|
||||
log(
|
||||
TAG,
|
||||
WARN
|
||||
) { "${rssi} ${scanResult.address} ${rawStatus.upperNibble.toBinaryString()} ${rawStatus.lowerNibble.toBinaryString()} primary=$primaryPod isCasePod=$isThisPodInThecase" }
|
||||
}
|
||||
}
|
||||
|
||||
if (factory == null && !SILENCED_PMS.contains(device.rawDeviceModel) && scanResult.address != "6E:9E:D1:49:D2:6D") {
|
||||
SILENCED_PMS.add(device.rawDeviceModel)
|
||||
|
||||
@@ -5,6 +5,9 @@ import eu.darken.capod.common.bluetooth.BleScanResult
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.DEBUG
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.lowerNibble
|
||||
import eu.darken.capod.common.toHex
|
||||
import eu.darken.capod.common.upperNibble
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.protocol.ContinuityProtocol
|
||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||
@@ -27,11 +30,20 @@ interface ApplePods : PodDevice {
|
||||
val rawStatus: UByte
|
||||
get() = proximityMessage.data[3]
|
||||
|
||||
val rawStatusHex: String
|
||||
get() = rawStatus.toHex()
|
||||
|
||||
val rawPodsBattery: UByte
|
||||
get() = proximityMessage.data[4]
|
||||
|
||||
val rawCaseBattery: UByte
|
||||
get() = proximityMessage.data[5]
|
||||
val rawPodsBatteryHex: String
|
||||
get() = rawPodsBattery.toHex()
|
||||
|
||||
val rawFlags: UShort
|
||||
get() = proximityMessage.data[5].upperNibble
|
||||
|
||||
val rawCaseBattery: UShort
|
||||
get() = proximityMessage.data[5].lowerNibble
|
||||
|
||||
val rawCaseLidState: UByte
|
||||
get() = proximityMessage.data[6]
|
||||
|
||||
@@ -14,17 +14,24 @@ import eu.darken.capod.pods.core.HasDualPods.Pod
|
||||
|
||||
interface DualApplePods : ApplePods, HasDualPods, HasDualEarDetection, HasCase {
|
||||
|
||||
val microPhonePod: Pod
|
||||
val primaryPod: Pod
|
||||
get() = when (rawStatus.isBitSet(5)) {
|
||||
true -> Pod.LEFT
|
||||
false -> Pod.RIGHT
|
||||
}
|
||||
|
||||
/**
|
||||
* Normally values for the left pod are in the lower nibbles, if the left pod is primary (microphone)
|
||||
* If the right pod is the primary, the values are flipped.
|
||||
*/
|
||||
val areValuesFlipped: Boolean
|
||||
get() = !rawStatus.isBitSet(5)
|
||||
|
||||
override val batteryLeftPodPercent: Float?
|
||||
get() {
|
||||
val value = when (microPhonePod) {
|
||||
Pod.LEFT -> rawPodsBattery.lowerNibble.toInt()
|
||||
Pod.RIGHT -> rawPodsBattery.upperNibble.toInt()
|
||||
val value = when (areValuesFlipped) {
|
||||
true -> rawPodsBattery.upperNibble.toInt()
|
||||
false -> rawPodsBattery.lowerNibble.toInt()
|
||||
}
|
||||
return when (value) {
|
||||
15 -> null
|
||||
@@ -39,9 +46,9 @@ interface DualApplePods : ApplePods, HasDualPods, HasDualEarDetection, HasCase {
|
||||
|
||||
override val batteryRightPodPercent: Float?
|
||||
get() {
|
||||
val value = when (microPhonePod) {
|
||||
Pod.LEFT -> rawPodsBattery.upperNibble.toInt()
|
||||
Pod.RIGHT -> rawPodsBattery.lowerNibble.toInt()
|
||||
val value = when (areValuesFlipped) {
|
||||
true -> rawPodsBattery.lowerNibble.toInt()
|
||||
false -> rawPodsBattery.upperNibble.toInt()
|
||||
}
|
||||
return when (value) {
|
||||
15 -> null
|
||||
@@ -53,32 +60,56 @@ interface DualApplePods : ApplePods, HasDualPods, HasDualEarDetection, HasCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isThisPodInThecase: Boolean
|
||||
get() = rawStatus.isBitSet(6)
|
||||
|
||||
val isOnePodInCase: Boolean
|
||||
get() = rawStatus.isBitSet(4)
|
||||
|
||||
val areBothPodsInCase: Boolean
|
||||
get() = rawStatus.isBitSet(2)
|
||||
|
||||
override val isLeftPodInEar: Boolean
|
||||
get() = when (microPhonePod) {
|
||||
Pod.LEFT -> rawStatus.isBitSet(1)
|
||||
Pod.RIGHT -> rawStatus.isBitSet(3)
|
||||
get() = when (areValuesFlipped xor isThisPodInThecase) {
|
||||
true -> rawStatus.isBitSet(3)
|
||||
false -> rawStatus.isBitSet(1)
|
||||
}
|
||||
|
||||
override val isRightPodInEar: Boolean
|
||||
get() = when (microPhonePod) {
|
||||
Pod.LEFT -> rawStatus.isBitSet(3)
|
||||
Pod.RIGHT -> rawStatus.isBitSet(1)
|
||||
get() = when (areValuesFlipped xor isThisPodInThecase) {
|
||||
true -> rawStatus.isBitSet(1)
|
||||
false -> rawStatus.isBitSet(3)
|
||||
}
|
||||
|
||||
/**
|
||||
* The data flip bit is set if the left pod is primary.
|
||||
* For the pod that is in the case, this is flipped again though.
|
||||
*/
|
||||
val isLeftPodMicrophone: Boolean
|
||||
get() = rawStatus.isBitSet(5) xor isThisPodInThecase
|
||||
|
||||
/**
|
||||
* The data flip bit is UNset if the right pod is primary.
|
||||
* For the pod that is in the case, this is flipped again though.
|
||||
*/
|
||||
val isRightPodMicrophone: Boolean
|
||||
get() = !rawStatus.isBitSet(5) xor isThisPodInThecase
|
||||
|
||||
val isLeftPodCharging: Boolean
|
||||
get() = when (microPhonePod) {
|
||||
Pod.LEFT -> rawCaseBattery.upperNibble.isBitSet(0)
|
||||
Pod.RIGHT -> rawCaseBattery.upperNibble.isBitSet(1)
|
||||
get() = when (areValuesFlipped) {
|
||||
false -> rawFlags.isBitSet(0)
|
||||
true -> rawFlags.isBitSet(1)
|
||||
}
|
||||
|
||||
val isRightPodCharging: Boolean
|
||||
get() = when (microPhonePod) {
|
||||
Pod.LEFT -> rawCaseBattery.upperNibble.isBitSet(1)
|
||||
Pod.RIGHT -> rawCaseBattery.upperNibble.isBitSet(0)
|
||||
get() = when (areValuesFlipped) {
|
||||
false -> rawFlags.isBitSet(1)
|
||||
true -> rawFlags.isBitSet(0)
|
||||
}
|
||||
|
||||
override val batteryCasePercent: Float?
|
||||
get() = when (val value = rawCaseBattery.lowerNibble.toInt()) {
|
||||
get() = when (val value = rawCaseBattery.toInt()) {
|
||||
15 -> null
|
||||
else -> if (value > 10) {
|
||||
log { "Case: Above 100% battery: $value" }
|
||||
@@ -89,7 +120,7 @@ interface DualApplePods : ApplePods, HasDualPods, HasDualEarDetection, HasCase {
|
||||
}
|
||||
|
||||
override val isCaseCharging: Boolean
|
||||
get() = rawCaseBattery.upperNibble.isBitSet(2)
|
||||
get() = rawFlags.isBitSet(2)
|
||||
|
||||
val caseLidState: LidState
|
||||
get() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package eu.darken.capod.pods.core.apple
|
||||
|
||||
import eu.darken.capod.common.isBitSet
|
||||
import eu.darken.capod.common.upperNibble
|
||||
import eu.darken.capod.pods.core.HasEarDetection
|
||||
import eu.darken.capod.pods.core.HasSinglePod
|
||||
|
||||
@@ -11,7 +10,7 @@ interface SingleApplePods : BasicSingleApplePods, HasEarDetection, HasSinglePod
|
||||
get() = rawStatus.isBitSet(1)
|
||||
|
||||
val isHeadsetBeingCharged: Boolean
|
||||
get() = rawCaseBattery.upperNibble.isBitSet(0)
|
||||
get() = rawFlags.isBitSet(0)
|
||||
|
||||
override val isBeingWorn: Boolean
|
||||
get() = isHeadphonesBeingWorn
|
||||
|
||||
@@ -19,7 +19,8 @@ object ProximityPairing {
|
||||
val vendor: UByte,
|
||||
val length: UByte,
|
||||
val device: UShort,
|
||||
val batteryData: Set<UByte>,
|
||||
val podBatteryData: Set<UShort>,
|
||||
val caseBatteryData: UShort,
|
||||
val deviceColor: UByte,
|
||||
)
|
||||
|
||||
@@ -28,7 +29,8 @@ object ProximityPairing {
|
||||
length = PROXIMITY_PAIRING_MESSAGE_LENGTH.toUByte(),
|
||||
device = (((data[1].toInt() and 255) shl 8) or (data[2].toInt() and 255)).toUShort(),
|
||||
// Make comparison order independent
|
||||
batteryData = setOf(data[4].upperNibble, data[4].lowerNibble),
|
||||
podBatteryData = setOf(data[4].upperNibble, data[4].lowerNibble),
|
||||
caseBatteryData = data[5].lowerNibble,
|
||||
deviceColor = data[7]
|
||||
)
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ class BasicSingleApplePodsTest : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0520.toUShort()
|
||||
rawStatus shouldBe 0x00.toUByte()
|
||||
rawPodsBattery shouldBe 0xF5.toUByte()
|
||||
rawCaseBattery shouldBe 0x0F.toUByte()
|
||||
rawFlags shouldBe 0x0.toUShort()
|
||||
rawCaseBattery shouldBe 0xF.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x01.toUByte()
|
||||
rawSuffix shouldBe 0x00.toUByte()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package eu.darken.capod.pods.core.apple
|
||||
|
||||
import eu.darken.capod.pods.core.HasDualPods
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import org.junit.jupiter.api.Test
|
||||
@@ -15,7 +14,8 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0e20.toUShort()
|
||||
rawStatus shouldBe 0x54.toUByte()
|
||||
rawPodsBattery shouldBe 0xAA.toUByte()
|
||||
rawCaseBattery shouldBe 0xB5.toUByte()
|
||||
rawFlags shouldBe 0xB.toUShort()
|
||||
rawCaseBattery shouldBe 0x5.toUShort()
|
||||
rawCaseLidState shouldBe 0x31.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x00.toUByte()
|
||||
@@ -27,12 +27,14 @@ class DualApplePodsTest : BaseAirPodsTest() {
|
||||
create<DualApplePods>("07 19 01 0E 20 >2B< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||
// 00101011
|
||||
// --^-----
|
||||
microPhonePod shouldBe HasDualPods.Pod.LEFT
|
||||
isLeftPodMicrophone shouldBe true
|
||||
isRightPodMicrophone shouldBe false
|
||||
}
|
||||
create<DualApplePods>("07 19 01 0E 20 >0B< AA B5 31 00 00 E0 0C A7 8A 60 4B D3 7D F4 60 4F 2C 73 E9 A7 F4") {
|
||||
// 00001011
|
||||
// --^-----
|
||||
microPhonePod shouldBe HasDualPods.Pod.RIGHT
|
||||
isLeftPodMicrophone shouldBe false
|
||||
isRightPodMicrophone shouldBe true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ class SingleApplePodsTest : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0A20.toUShort()
|
||||
rawStatus shouldBe 0x62.toUByte()
|
||||
rawPodsBattery shouldBe 0x04.toUByte()
|
||||
rawCaseBattery shouldBe 0x80.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0x0.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x0F.toUByte()
|
||||
rawSuffix shouldBe 0x40.toUByte()
|
||||
|
||||
@@ -16,7 +16,8 @@ class AirPodsGen1Test : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0220.toUShort()
|
||||
rawStatus shouldBe 0x55.toUByte()
|
||||
rawPodsBattery shouldBe 0xAF.toUByte()
|
||||
rawCaseBattery shouldBe 0x56.toUByte()
|
||||
rawFlags shouldBe 0x5.toUShort()
|
||||
rawCaseBattery shouldBe 0x6.toUShort()
|
||||
rawCaseLidState shouldBe 0x31.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x00.toUByte()
|
||||
|
||||
@@ -15,7 +15,8 @@ class AirPodsGen2Test : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0F20.toUShort()
|
||||
rawStatus shouldBe 0x02.toUByte()
|
||||
rawPodsBattery shouldBe 0xF9.toUByte()
|
||||
rawCaseBattery shouldBe 0x8F.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0xF.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x05.toUByte()
|
||||
|
||||
@@ -15,7 +15,8 @@ class AirPodsGen3Test : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x1320.toUShort()
|
||||
rawStatus shouldBe 0x75.toUByte()
|
||||
rawPodsBattery shouldBe 0xAA.toUByte()
|
||||
rawCaseBattery shouldBe 0xB9.toUByte()
|
||||
rawFlags shouldBe 0xB.toUShort()
|
||||
rawCaseBattery shouldBe 0x9.toUShort()
|
||||
rawCaseLidState shouldBe 0x31.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x04.toUByte()
|
||||
|
||||
@@ -15,7 +15,8 @@ class AirPodsMaxTest : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0A20.toUShort()
|
||||
rawStatus shouldBe 0x62.toUByte()
|
||||
rawPodsBattery shouldBe 0x04.toUByte()
|
||||
rawCaseBattery shouldBe 0x80.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0x0.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x0F.toUByte()
|
||||
rawSuffix shouldBe 0x40.toUByte()
|
||||
@@ -36,7 +37,8 @@ class AirPodsMaxTest : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0A20.toUShort()
|
||||
rawStatus shouldBe 0x02.toUByte()
|
||||
rawPodsBattery shouldBe 0x05.toUByte()
|
||||
rawCaseBattery shouldBe 0x80.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0x0.toUShort()
|
||||
rawCaseLidState shouldBe 0x04.toUByte()
|
||||
rawDeviceColor shouldBe 0x0F.toUByte()
|
||||
rawSuffix shouldBe 0x44.toUByte()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package eu.darken.capod.pods.core.apple.airpods
|
||||
|
||||
import eu.darken.capod.pods.core.HasDualPods
|
||||
import eu.darken.capod.pods.core.apple.BaseAirPodsTest
|
||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
||||
import io.kotest.matchers.shouldBe
|
||||
@@ -17,12 +16,14 @@ class AirPodsProTest : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0e20.toUShort()
|
||||
rawStatus shouldBe 0x54.toUByte()
|
||||
rawPodsBattery shouldBe 0xAA.toUByte()
|
||||
rawCaseBattery shouldBe 0xB5.toUByte()
|
||||
rawFlags shouldBe 0xB.toUShort()
|
||||
rawCaseBattery shouldBe 0x5.toUShort()
|
||||
rawCaseLidState shouldBe 0x31.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x00.toUByte()
|
||||
|
||||
microPhonePod shouldBe HasDualPods.Pod.RIGHT
|
||||
isLeftPodMicrophone shouldBe true
|
||||
isRightPodMicrophone shouldBe false
|
||||
|
||||
batteryLeftPodPercent shouldBe 1.0f
|
||||
batteryRightPodPercent shouldBe 1.0f
|
||||
@@ -39,7 +40,8 @@ class AirPodsProTest : BaseAirPodsTest() {
|
||||
@Test
|
||||
fun `test AirPods from my downstairs neighbour`() = runBlockingTest {
|
||||
create<AirPodsPro>("07 19 01 0E 20 00 F3 8F 02 00 04 79 C6 3F F9 C3 15 D9 11 A1 3C B1 58 66 B9 8B 67") {
|
||||
microPhonePod shouldBe HasDualPods.Pod.RIGHT
|
||||
isLeftPodMicrophone shouldBe false
|
||||
isRightPodMicrophone shouldBe true
|
||||
|
||||
batteryLeftPodPercent shouldBe null
|
||||
batteryRightPodPercent shouldBe 0.3f
|
||||
|
||||
@@ -15,7 +15,8 @@ class BeatsFlexText : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x1020.toUShort()
|
||||
rawStatus shouldBe 0x0A.toUByte()
|
||||
rawPodsBattery shouldBe 0xF4.toUByte()
|
||||
rawCaseBattery shouldBe 0x8F.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0xF.toUShort()
|
||||
rawCaseLidState shouldBe 0x00.toUByte()
|
||||
rawDeviceColor shouldBe 0x01.toUByte()
|
||||
rawSuffix shouldBe 0x00.toUByte()
|
||||
|
||||
@@ -15,7 +15,8 @@ class BeatsSolo3Test : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0620.toUShort()
|
||||
rawStatus shouldBe 0x62.toUByte()
|
||||
rawPodsBattery shouldBe 0x04.toUByte()
|
||||
rawCaseBattery shouldBe 0x80.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0x0.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x0F.toUByte()
|
||||
rawSuffix shouldBe 0x40.toUByte()
|
||||
|
||||
@@ -15,7 +15,8 @@ class BeatsStudio3Test : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0920.toUShort()
|
||||
rawStatus shouldBe 0x62.toUByte()
|
||||
rawPodsBattery shouldBe 0x04.toUByte()
|
||||
rawCaseBattery shouldBe 0x80.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0x0.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x0F.toUByte()
|
||||
rawSuffix shouldBe 0x40.toUByte()
|
||||
|
||||
@@ -15,7 +15,8 @@ class BeatsXTest : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0520.toUShort()
|
||||
rawStatus shouldBe 0x00.toUByte()
|
||||
rawPodsBattery shouldBe 0xF5.toUByte()
|
||||
rawCaseBattery shouldBe 0x0F.toUByte()
|
||||
rawFlags shouldBe 0x0.toUShort()
|
||||
rawCaseBattery shouldBe 0xF.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x01.toUByte()
|
||||
rawSuffix shouldBe 0x00.toUByte()
|
||||
|
||||
@@ -15,7 +15,8 @@ class PowerBeats3Test : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0320.toUShort()
|
||||
rawStatus shouldBe 0x62.toUByte()
|
||||
rawPodsBattery shouldBe 0x04.toUByte()
|
||||
rawCaseBattery shouldBe 0x80.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0x0.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x0F.toUByte()
|
||||
rawSuffix shouldBe 0x40.toUByte()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package eu.darken.capod.pods.core.apple.beats
|
||||
|
||||
import eu.darken.capod.pods.core.HasDualPods
|
||||
import eu.darken.capod.pods.core.apple.BaseAirPodsTest
|
||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
||||
import io.kotest.matchers.shouldBe
|
||||
@@ -17,12 +16,14 @@ class PowerBeatsProTest : BaseAirPodsTest() {
|
||||
rawDeviceModel shouldBe 0x0B20.toUShort()
|
||||
rawStatus shouldBe 0x54.toUByte()
|
||||
rawPodsBattery shouldBe 0xAA.toUByte()
|
||||
rawCaseBattery shouldBe 0xB5.toUByte()
|
||||
rawFlags shouldBe 0xB.toUShort()
|
||||
rawCaseBattery shouldBe 0x5.toUShort()
|
||||
rawCaseLidState shouldBe 0x31.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x00.toUByte()
|
||||
|
||||
microPhonePod shouldBe HasDualPods.Pod.RIGHT
|
||||
isLeftPodMicrophone shouldBe true
|
||||
isRightPodMicrophone shouldBe false
|
||||
|
||||
batteryLeftPodPercent shouldBe 1.0f
|
||||
batteryRightPodPercent shouldBe 1.0f
|
||||
|
||||
Reference in New Issue
Block a user