-
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #489 from handymenny/shannon-lte
Add initial support for ShannonLteUeCap
- Loading branch information
Showing
24 changed files
with
530,588 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
src/main/java/it/smartphonecombo/uecapabilityparser/importer/ImportShannonLteUeCap.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
@file:OptIn(ExperimentalSerializationApi::class) | ||
|
||
package it.smartphonecombo.uecapabilityparser.importer | ||
|
||
import it.smartphonecombo.uecapabilityparser.extension.mutableListWithCapacity | ||
import it.smartphonecombo.uecapabilityparser.io.InputSource | ||
import it.smartphonecombo.uecapabilityparser.model.Capabilities | ||
import it.smartphonecombo.uecapabilityparser.model.combo.ComboLte | ||
import it.smartphonecombo.uecapabilityparser.model.component.ComponentLte | ||
import it.smartphonecombo.uecapabilityparser.model.shannon.lte.ShannonComboLte | ||
import it.smartphonecombo.uecapabilityparser.model.shannon.lte.ShannonComponentLte | ||
import it.smartphonecombo.uecapabilityparser.model.shannon.lte.ShannonLteUECap | ||
import kotlinx.serialization.ExperimentalSerializationApi | ||
import kotlinx.serialization.decodeFromByteArray | ||
import kotlinx.serialization.protobuf.ProtoBuf | ||
|
||
object ImportShannonLteUeCap : ImportCapabilities { | ||
override fun parse(input: InputSource): Capabilities { | ||
val capabilities = Capabilities() | ||
val byteArray = input.readBytes() | ||
val lteUECap = ProtoBuf.decodeFromByteArray<ShannonLteUECap>(byteArray) | ||
|
||
capabilities.setMetadata("shannonUeCapVersion", lteUECap.version) | ||
|
||
val list = mutableListWithCapacity<ComboLte>(lteUECap.combos.size) | ||
for (combo in lteUECap.combos) { | ||
list.add(processShannonCombo(combo)) | ||
} | ||
|
||
capabilities.lteCombos = list | ||
|
||
return capabilities | ||
} | ||
|
||
private fun processShannonCombo(shCombo: ShannonComboLte): ComboLte { | ||
val lteComponents = shCombo.components | ||
val lte = processShannonComponentsLte(lteComponents) | ||
val bcs = shCombo.bcs | ||
|
||
val combo = ComboLte(lte, bcs) | ||
return combo | ||
} | ||
|
||
private fun processShannonComponentsLte( | ||
shComponents: List<ShannonComponentLte> | ||
): List<ComponentLte> { | ||
val components = shComponents.map { processShannonComponentLte(it) } | ||
|
||
return components.sortedDescending() | ||
} | ||
|
||
private fun processShannonComponentLte(shComponent: ShannonComponentLte): ComponentLte { | ||
return shComponent.toComponent() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
src/main/java/it/smartphonecombo/uecapabilityparser/model/shannon/lte/ShannonComboLte.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
@file:OptIn(ExperimentalSerializationApi::class) | ||
|
||
package it.smartphonecombo.uecapabilityparser.model.shannon.lte | ||
|
||
import it.smartphonecombo.uecapabilityparser.model.BCS | ||
import it.smartphonecombo.uecapabilityparser.model.EmptyBCS | ||
import kotlinx.serialization.ExperimentalSerializationApi | ||
import kotlinx.serialization.SerialName | ||
import kotlinx.serialization.Serializable | ||
import kotlinx.serialization.protobuf.ProtoNumber | ||
|
||
@Serializable | ||
@SerialName("Combo") | ||
data class ShannonComboLte( | ||
/** List of Components. */ | ||
@ProtoNumber(1) val components: List<ShannonComponentLte> = emptyList(), | ||
/** | ||
* The supportedBandwidthCombinationSet of this combo. | ||
* | ||
* It's stored as a 32bit unsigned int, each of its bits has the same value of the corresponding | ||
* bit in the BitString. 0 means default i.e. only BCS 0 supported (if applicable). | ||
*/ | ||
@ProtoNumber(2) @SerialName("bcs") private val rawBcs: Long? = null, | ||
@ProtoNumber(3) val unknown1: Long, | ||
@ProtoNumber(4) val unknown2: Long | ||
) { | ||
val bcs | ||
get() = | ||
when (rawBcs) { | ||
0L -> BCS.fromQualcommCP("0") | ||
null -> EmptyBCS | ||
else -> rawBcs.toString(2).padStart(32, '0').let { BCS.fromBinaryString(it) } | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
src/main/java/it/smartphonecombo/uecapabilityparser/model/shannon/lte/ShannonComponentLte.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
@file:OptIn(ExperimentalSerializationApi::class) | ||
|
||
package it.smartphonecombo.uecapabilityparser.model.shannon.lte | ||
|
||
import it.smartphonecombo.uecapabilityparser.model.BwClass | ||
import it.smartphonecombo.uecapabilityparser.model.LinkDirection | ||
import it.smartphonecombo.uecapabilityparser.model.Mimo | ||
import it.smartphonecombo.uecapabilityparser.model.component.ComponentLte | ||
import it.smartphonecombo.uecapabilityparser.model.toMimo | ||
import kotlinx.serialization.ExperimentalSerializationApi | ||
import kotlinx.serialization.SerialName | ||
import kotlinx.serialization.Serializable | ||
import kotlinx.serialization.protobuf.ProtoNumber | ||
|
||
@Serializable | ||
@SerialName("Component") | ||
data class ShannonComponentLte( | ||
/** LTE Bands are stored as int. */ | ||
@ProtoNumber(1) @SerialName("band") private val band: Int, | ||
/** | ||
* First 8 bits encode mimo, second 8 bits encode bw class. Bw class is encoded setting to 1 the | ||
* bit representing the bw class index. Ex. 1000 0000 = class A (index 0), 0100 0000 = class B | ||
* (index 1), 00100 0000 = class C (index 2) | ||
* | ||
* Mimo is encoded as enum, 0 -> 2, 1 -> 4 | ||
*/ | ||
@ProtoNumber(2) @SerialName("bwClassMimoDl") private val rawBwClassMimoDl: Int, | ||
/** | ||
* First 8 bits encode mimo, second 8 bits encode bw class. Bw class is encoded setting to 1 the | ||
* bit representing the bw class index. Ex. 1000 0000 = class A (index 0), 0100 0000 = class B | ||
* (index 1), 00100 0000 = class C (index 2) | ||
* | ||
* Mimo is encoded as enum, 0 -> 1, 1 -> 2 | ||
*/ | ||
@ProtoNumber(3) @SerialName("bwClassMimoUl") private val rawBwClassMimoUl: Int, | ||
) { | ||
|
||
val bwClassDl: BwClass | ||
get() = fromRawToBwClass(rawBwClassMimoDl) | ||
|
||
val bwClassUl: BwClass | ||
get() = fromRawToBwClass(rawBwClassMimoUl) | ||
|
||
val mimoDl: Mimo | ||
get() = fromRawToMimo(rawBwClassMimoDl, LinkDirection.DOWNLINK) | ||
|
||
val mimoUl: Mimo | ||
get() = fromRawToMimo(rawBwClassMimoUl, LinkDirection.UPLINK) | ||
|
||
fun toComponent(): ComponentLte { | ||
return ComponentLte(band, bwClassDl, bwClassUl, mimoDl, mimoUl) | ||
} | ||
|
||
private fun fromRawToMimo(raw: Int, direction: LinkDirection): Mimo { | ||
val mimoIndex = (raw and 0xF) + 1 | ||
val shift = if (direction == LinkDirection.DOWNLINK) 1 else 0 | ||
|
||
val mimo = mimoIndex shl shift | ||
|
||
return mimo.toMimo() | ||
} | ||
|
||
private fun fromRawToBwClass(raw: Int): BwClass { | ||
// bits 8 - 15 | ||
val upperHalf = raw shr 8 and 0xFF | ||
val bitString = upperHalf.toString(2).padStart(8, '0') | ||
|
||
// get position of first 1 | ||
val indexOfFirstOne = bitString.indexOf("1") + 1 | ||
|
||
return BwClass.valueOf(indexOfFirstOne) | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
src/main/java/it/smartphonecombo/uecapabilityparser/model/shannon/lte/ShannonLteUECap.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
@file:OptIn(ExperimentalSerializationApi::class) | ||
|
||
package it.smartphonecombo.uecapabilityparser.model.shannon.lte | ||
|
||
import kotlinx.serialization.ExperimentalSerializationApi | ||
import kotlinx.serialization.SerialName | ||
import kotlinx.serialization.Serializable | ||
import kotlinx.serialization.protobuf.ProtoNumber | ||
|
||
/** | ||
* This is the result of reverse-engineering Shannon Ue Cap Configs stored as binary protobufs in | ||
* Google Pixel firmware. | ||
* | ||
* See also ShannonLteUeCap.proto in src/main/resources/definition. | ||
* | ||
* This work wouldn't have been possible without the help of @NXij. | ||
*/ | ||
@Serializable | ||
@SerialName("ShannonLteUECap") | ||
data class ShannonLteUECap( | ||
/** ShannonUECapLte version. */ | ||
@ProtoNumber(1) val version: Long, | ||
/** List of combos. */ | ||
@ProtoNumber(2) val combos: List<ShannonComboLte> = emptyList(), | ||
@ProtoNumber(3) val bitmask: Long, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
syntax = "proto2"; | ||
|
||
message ShannonLteUECap { | ||
// ShannonUECapLte version. | ||
required uint32 version = 1; | ||
// List of combos. | ||
repeated Combo combos = 2; | ||
// Unknown bitmask. | ||
required uint32 bitmask = 3; | ||
} | ||
|
||
message Combo { | ||
// List of Components. | ||
repeated Component components = 1; | ||
/* | ||
The supportedBandwidthCombinationSet of this combo. | ||
It's stored as a 32bit unsigned int, each of its bits has the same value of the corresponding | ||
bit in the BitString. 0 means default i.e. only BCS 0 supported (if applicable). | ||
*/ | ||
optional uint32 bcs = 2; | ||
// Unknown bitmask. | ||
required uint32 unknown1 = 3; | ||
// Unknown bitmask. | ||
required uint32 unknown2 = 4; | ||
} | ||
|
||
message Component { | ||
// LTE Bands are stored as int | ||
required int32 band = 1; | ||
/* | ||
First 8 bits encode mimo, second 8 bits encode bw class. Bw class is encoded setting to 1 the | ||
bit representing the bw class index. | ||
Ex. 1000 0000 = class A (index 0), 0100 0000 = class B (index 1), 00100 0000 = class C (index 2) | ||
Mimo is encoded as enum, 0 -> 2, 1 -> 4 | ||
*/ | ||
required int32 bwClassMimoDl = 2; | ||
/* | ||
First 8 bits encode mimo, second 8 bits encode bw class. Bw class is encoded setting to 1 the | ||
bit representing the bw class index. | ||
Ex. 1000 0000 = class A (index 0), 0100 0000 = class B (index 1), 00100 0000 = class C (index 2) | ||
Mimo is encoded as enum, 0 -> 1, 1 -> 2 | ||
*/ | ||
required int32 bwClassMimoUl = 3; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
src/test/java/it/smartphonecombo/uecapabilityparser/importer/ImportShannonLteUeCapTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package it.smartphonecombo.uecapabilityparser.importer | ||
|
||
import it.smartphonecombo.uecapabilityparser.extension.toInputSource | ||
import it.smartphonecombo.uecapabilityparser.model.Capabilities | ||
import java.io.File | ||
import kotlinx.serialization.json.Json | ||
import org.junit.jupiter.api.Assertions | ||
import org.junit.jupiter.api.Test | ||
|
||
internal class ImportShannonLteUeCapTest { | ||
private val path = "src/test/resources/shannon/" | ||
|
||
private fun parse(inputFilename: String, oracleFilename: String) { | ||
val filePath = "$path/input/$inputFilename" | ||
val actual = ImportShannonLteUeCap.parse(File(filePath).toInputSource()) | ||
val expected = | ||
Json.decodeFromString<Capabilities>( | ||
File("$path/oracleForImport/$oracleFilename").readText() | ||
) | ||
|
||
Assertions.assertEquals(expected, actual) | ||
} | ||
|
||
@Test | ||
fun parseLte() { | ||
parse("lte.binarypb", "lte.json") | ||
} | ||
|
||
@Test | ||
fun parseLte2() { | ||
parse("lte2.binarypb", "lte2.json") | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
src/test/java/it/smartphonecombo/uecapabilityparser/model/ShannonComponentLteTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package it.smartphonecombo.uecapabilityparser.model | ||
|
||
import it.smartphonecombo.uecapabilityparser.model.shannon.lte.ShannonComponentLte | ||
import org.junit.jupiter.api.Assertions.assertEquals | ||
import org.junit.jupiter.api.Test | ||
|
||
internal class ShannonComponentLteTest { | ||
|
||
@Test | ||
fun testBwClass() { | ||
val classDMimo2 = 0b0001_0000_0000_0000 | ||
val classAMimo1 = 0b1000_0000_0000_0000 | ||
val componentLte = ShannonComponentLte(1, classDMimo2, classAMimo1) | ||
|
||
assertEquals("D".toBwClass(), componentLte.bwClassDl) | ||
assertEquals("A".toBwClass(), componentLte.bwClassUl) | ||
} | ||
|
||
@Test | ||
fun testMimo() { | ||
val classAMimo4 = 0b0001_0000_0000_0001 | ||
val classAMimo2 = 0b1000_0000_0000_0001 | ||
val componentLte = ShannonComponentLte(1, classAMimo4, classAMimo2) | ||
|
||
assertEquals(4.toMimo(), componentLte.mimoDl) | ||
assertEquals(2.toMimo(), componentLte.mimoUl) | ||
} | ||
|
||
@Test | ||
fun testBwClassNone() { | ||
val classBMimo2 = 0b0100_0000_0000_0000 | ||
|
||
val componentLte = ShannonComponentLte(3, classBMimo2, 0) | ||
|
||
assertEquals("B".toBwClass(), componentLte.bwClassDl) | ||
assertEquals(BwClass.NONE, componentLte.bwClassUl) | ||
} | ||
} |
Oops, something went wrong.