mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
fix(popup): decode lid state from case context
This commit is contained in:
@@ -144,11 +144,11 @@ interface DualApplePods : ApplePods, HasChargeDetectionDual, DualBlePodSnapshot,
|
||||
return pubFlags.isBitSet(2)
|
||||
}
|
||||
|
||||
val hasCaseContext: Boolean
|
||||
get() = isThisPodInThecase || isOnePodInCase || areBothPodsInCase
|
||||
|
||||
val caseLidState: LidState
|
||||
get() {
|
||||
val rawstate = pubCaseLidState
|
||||
return LidState.entries.firstOrNull { it.rawRange.contains(rawstate.toInt()) } ?: LidState.UNKNOWN
|
||||
}
|
||||
get() = LidState.fromRaw(pubCaseLidState, hasCaseContext)
|
||||
|
||||
/**
|
||||
* TODO this is glitchy
|
||||
@@ -158,11 +158,23 @@ interface DualApplePods : ApplePods, HasChargeDetectionDual, DualBlePodSnapshot,
|
||||
* They reset after some time to their start values.
|
||||
* The upper limits are not the maximums but are only reached if playing with the case.
|
||||
*/
|
||||
enum class LidState(val rawRange: IntRange) {
|
||||
OPEN(0x30..0x37),
|
||||
CLOSED(0x38..0x3F),
|
||||
NOT_IN_CASE(0x00..0x03),
|
||||
UNKNOWN(0xFF..0xFF);
|
||||
enum class LidState {
|
||||
OPEN,
|
||||
CLOSED,
|
||||
NOT_IN_CASE,
|
||||
UNKNOWN;
|
||||
|
||||
companion object {
|
||||
fun fromRaw(raw: UByte, hasCaseContext: Boolean): LidState {
|
||||
if (!hasCaseContext) return NOT_IN_CASE
|
||||
|
||||
return when ((raw.toInt() shr 3) and 0x01) {
|
||||
0 -> OPEN
|
||||
1 -> CLOSED
|
||||
else -> UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package eu.darken.capod.pods.core.apple.ble.devices
|
||||
|
||||
import eu.darken.capod.common.bluetooth.BleScanResult
|
||||
import eu.darken.capod.pods.core.apple.ble.devices.airpods.AirPodsPro
|
||||
import eu.darken.capod.pods.core.apple.ble.devices.airpods.HasStateDetectionAirPods
|
||||
import eu.darken.capod.pods.core.apple.ble.protocol.ProximityPayload
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.time.Instant
|
||||
|
||||
class DualApplePodsTest : BaseBlePodsTest() {
|
||||
|
||||
@@ -210,6 +214,45 @@ class DualApplePodsTest : BaseBlePodsTest() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun directAirPodsPro(
|
||||
status: Int,
|
||||
rawCaseLidState: Int,
|
||||
) = AirPodsPro(
|
||||
scanResult = BleScanResult(
|
||||
receivedAt = Instant.parse("2026-01-01T00:00:00Z"),
|
||||
address = "77:49:4C:D8:25:0C",
|
||||
rssi = -66,
|
||||
generatedAtNanos = 136136027721826,
|
||||
manufacturerSpecificData = mutableMapOf(),
|
||||
),
|
||||
payload = ProximityPayload(
|
||||
public = ProximityPayload.Public(
|
||||
ubyteArrayOf(
|
||||
0x01u,
|
||||
0x0Eu,
|
||||
0x20u,
|
||||
status.toUByte(),
|
||||
0x89u,
|
||||
0xB3u,
|
||||
rawCaseLidState.toUByte(),
|
||||
0x00u,
|
||||
0x00u,
|
||||
)
|
||||
),
|
||||
private = null,
|
||||
),
|
||||
meta = ApplePods.AppleMeta(),
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `test AirPodDevice - case lid uses status derived case context`() {
|
||||
directAirPodsPro(status = 0x10, rawCaseLidState = 0x51).caseLidState shouldBe DualApplePods.LidState.OPEN
|
||||
directAirPodsPro(status = 0x04, rawCaseLidState = 0x5A).caseLidState shouldBe DualApplePods.LidState.CLOSED
|
||||
directAirPodsPro(status = 0x40, rawCaseLidState = 0x51).caseLidState shouldBe DualApplePods.LidState.OPEN
|
||||
directAirPodsPro(status = 0x2B, rawCaseLidState = 0x11).caseLidState shouldBe DualApplePods.LidState.NOT_IN_CASE
|
||||
directAirPodsPro(status = 0x20, rawCaseLidState = 0x5A).caseLidState shouldBe DualApplePods.LidState.NOT_IN_CASE
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test AirPodDevice - connection state`() = runTest {
|
||||
// Disconnected
|
||||
@@ -244,4 +287,4 @@ class DualApplePodsTest : BaseBlePodsTest() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user