Implemented all seven packet types.
This commit is contained in:
parent
bc6da05747
commit
c9704c4bf4
3 changed files with 240 additions and 71 deletions
|
@ -1,7 +1,10 @@
|
||||||
package club.clubk.ktag.bletool
|
package club.clubk.ktag.bletool
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
data class ByteCellData(
|
data class ByteCellData(
|
||||||
val value: Byte,
|
val value: Byte,
|
||||||
val isHeader: Boolean,
|
val isHeader: Boolean,
|
||||||
val description: String
|
val description: String,
|
||||||
|
val backgroundColor: Color? = null
|
||||||
)
|
)
|
|
@ -15,12 +15,15 @@ import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
@ -49,12 +52,8 @@ import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.compose.foundation.border
|
|
||||||
import androidx.compose.foundation.layout.*
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
|
||||||
private const val TAG = "BLE Tool"
|
private const val TAG = "BLE Tool"
|
||||||
|
|
||||||
|
@ -95,7 +94,7 @@ val advertisementPresets = listOf(
|
||||||
0x00.toByte(),
|
0x00.toByte(),
|
||||||
0x00.toByte(), // Event Data
|
0x00.toByte(), // Event Data
|
||||||
),
|
),
|
||||||
"KTag Instigate Game Packet"
|
"KTag Event Packet"
|
||||||
),
|
),
|
||||||
AdvertisementPreset(
|
AdvertisementPreset(
|
||||||
"03 Tag",
|
"03 Tag",
|
||||||
|
@ -146,10 +145,64 @@ val advertisementPresets = listOf(
|
||||||
),
|
),
|
||||||
"KTag Status Packet"
|
"KTag Status Packet"
|
||||||
),
|
),
|
||||||
|
AdvertisementPreset(
|
||||||
|
"06 Configuration",
|
||||||
|
byteArrayOf(
|
||||||
|
0x06.toByte(), // Packet Type: Configuration
|
||||||
|
0x00.toByte(), // Event Number
|
||||||
|
0xFF.toByte(),
|
||||||
|
0xFF.toByte(),
|
||||||
|
0xFF.toByte(),
|
||||||
|
0xFF.toByte(),
|
||||||
|
0xFF.toByte(),
|
||||||
|
0xFF.toByte(), // Target Bluetooth Device Address
|
||||||
|
0x02.toByte(), // Subtype: Request Parameter Change
|
||||||
|
0x01.toByte(),
|
||||||
|
0x00.toByte(), // Key 1: Team ID
|
||||||
|
0x02.toByte(),
|
||||||
|
0x00.toByte(),
|
||||||
|
0x00.toByte(),
|
||||||
|
0x00.toByte(), // Value 1: 2
|
||||||
|
0xFF.toByte(),
|
||||||
|
0xFF.toByte(), // Key 2: Unused
|
||||||
|
0x00.toByte(),
|
||||||
|
0x00.toByte(),
|
||||||
|
0x00.toByte(),
|
||||||
|
0x00.toByte(), // Value 2: Unused
|
||||||
|
),
|
||||||
|
"KTag Configuration Packet"
|
||||||
|
),
|
||||||
|
AdvertisementPreset(
|
||||||
|
"07 Hello",
|
||||||
|
byteArrayOf(
|
||||||
|
0x07.toByte(), // Packet Type: Hello
|
||||||
|
0x00.toByte(), // Event Number
|
||||||
|
0x01.toByte(), // SystemK Major Version
|
||||||
|
0x00.toByte(), // SystemK Minor Version
|
||||||
|
0x02.toByte(), //
|
||||||
|
0x00.toByte(), // Device Type: Mobile App
|
||||||
|
0x02.toByte(), // Team ID
|
||||||
|
0x4B.toByte(), // 'K'
|
||||||
|
0x54.toByte(), // 'T'
|
||||||
|
0x61.toByte(), // 'a'
|
||||||
|
0x67.toByte(), // 'g'
|
||||||
|
0x20.toByte(), // ' '
|
||||||
|
0x42.toByte(), // 'B'
|
||||||
|
0x4C.toByte(), // 'L'
|
||||||
|
0x45.toByte(), // 'E'
|
||||||
|
0x20.toByte(), // ' '
|
||||||
|
0x54.toByte(), // 'T'
|
||||||
|
0x6F.toByte(), // 'o'
|
||||||
|
0x6F.toByte(), // 'o'
|
||||||
|
0x6C.toByte(), // 'l'
|
||||||
|
0x00.toByte(), // Device Name: "KTag BLE Tool"
|
||||||
|
),
|
||||||
|
"KTag Hello Packet"
|
||||||
|
),
|
||||||
AdvertisementPreset(
|
AdvertisementPreset(
|
||||||
"Empty",
|
"Empty",
|
||||||
ByteArray(23) { 0 },
|
ByteArray(23) { 0 },
|
||||||
"All zeros - clear current data"
|
"All zeros (clear current data)"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -326,71 +379,13 @@ fun BleAdvertiserScreen() {
|
||||||
|
|
||||||
// Create list of byte cells with their properties
|
// Create list of byte cells with their properties
|
||||||
val byteCells = remember(advertisementData) {
|
val byteCells = remember(advertisementData) {
|
||||||
|
val packetType = advertisementData[8]
|
||||||
advertisementData.mapIndexed { index, byte ->
|
advertisementData.mapIndexed { index, byte ->
|
||||||
ByteCellData(
|
ByteCellData(
|
||||||
value = byte, isHeader = index < N_HEADER_BYTES, description = when (index) {
|
value = byte,
|
||||||
0 -> "Length" // Always "Length"
|
isHeader = index < N_HEADER_BYTES,
|
||||||
1 -> "Type" // Always "Type"
|
description = PacketFieldUtils.getFieldDescription(packetType, index),
|
||||||
2 -> "Mfg ID" // Always "Mfg ID"
|
backgroundColor = PacketFieldUtils.getFieldColor(packetType, index)
|
||||||
3 -> "Mfg ID" // Always "Mfg ID"
|
|
||||||
4 -> "'K'" // Always "'K'"
|
|
||||||
5 -> "'T'" // Always "'T'"
|
|
||||||
6 -> "'a'" // Always "'a'"
|
|
||||||
7 -> "'g'" // Always "'g'"
|
|
||||||
9 -> "Event Number"
|
|
||||||
else -> {
|
|
||||||
when (advertisementData[8]) {
|
|
||||||
0x01.toByte() -> when(index){
|
|
||||||
8 -> "Instigate Game" // Packet Type 01
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
0x02.toByte() -> when(index){
|
|
||||||
8 -> "Event" // Packet Type 02
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
0x03.toByte() -> when(index){
|
|
||||||
8 -> "Tag" // Packet Type 03
|
|
||||||
10 -> "Tx Pwr (dBm)"
|
|
||||||
11 -> "Protocol"
|
|
||||||
12 -> "Team ID"
|
|
||||||
13 -> "Player ID"
|
|
||||||
14 -> "Damage"
|
|
||||||
15 -> "Damage"
|
|
||||||
16 -> "Color"
|
|
||||||
17 -> "Color"
|
|
||||||
18 -> "Color"
|
|
||||||
19 -> "Color"
|
|
||||||
20 -> "Target Address"
|
|
||||||
21 -> "Target Address"
|
|
||||||
22 -> "Target Address"
|
|
||||||
23 -> "Target Address"
|
|
||||||
24 -> "Target Address"
|
|
||||||
25 -> "Target Address"
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
0x04.toByte() -> when(index){
|
|
||||||
8 -> "Console" // Packet Type 04
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
0x05.toByte() -> when(index){
|
|
||||||
8 -> "Status" // Packet Type 05
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
0x06.toByte() -> when(index){
|
|
||||||
8 -> "Configuration" // Packet Type 06
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
0x07.toByte() -> when(index){
|
|
||||||
8 -> "Hello" // Packet Type 07
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
else -> when(index){
|
|
||||||
8 -> "Packet Type"
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,6 +551,7 @@ fun ByteCell(
|
||||||
val backgroundColor = when {
|
val backgroundColor = when {
|
||||||
data.isHeader -> MaterialTheme.colorScheme.secondaryContainer
|
data.isHeader -> MaterialTheme.colorScheme.secondaryContainer
|
||||||
isSelected -> MaterialTheme.colorScheme.primary
|
isSelected -> MaterialTheme.colorScheme.primary
|
||||||
|
data.backgroundColor != null -> data.backgroundColor
|
||||||
else -> MaterialTheme.colorScheme.primaryContainer
|
else -> MaterialTheme.colorScheme.primaryContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
170
app/src/main/java/club/clubk/ktag/bletool/PacketFieldUtils.kt
Normal file
170
app/src/main/java/club/clubk/ktag/bletool/PacketFieldUtils.kt
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
package club.clubk.ktag.bletool
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
object PacketFieldUtils {
|
||||||
|
fun getFieldDescription(packetType: Byte, index: Int): String {
|
||||||
|
return when (index) {
|
||||||
|
0 -> "Length" // Always "Length"
|
||||||
|
1 -> "Type" // Always "Type"
|
||||||
|
2 -> "Mfg ID" // Always "Mfg ID"
|
||||||
|
3 -> "Mfg ID" // Always "Mfg ID"
|
||||||
|
4 -> "'K'" // Always "'K'"
|
||||||
|
5 -> "'T'" // Always "'T'"
|
||||||
|
6 -> "'a'" // Always "'a'"
|
||||||
|
7 -> "'g'" // Always "'g'"
|
||||||
|
8 -> when (packetType) {
|
||||||
|
0x01.toByte() -> "Instigate Game"
|
||||||
|
0x02.toByte() -> "Event"
|
||||||
|
0x03.toByte() -> "Tag"
|
||||||
|
0x04.toByte() -> "Console"
|
||||||
|
0x05.toByte() -> "Status"
|
||||||
|
0x06.toByte() -> "Configuration"
|
||||||
|
0x07.toByte() -> "Hello"
|
||||||
|
else -> "Packet Type"
|
||||||
|
}
|
||||||
|
|
||||||
|
9 -> "Event Number"
|
||||||
|
else -> when (packetType) {
|
||||||
|
0x01.toByte() -> when (index) { // Instigate Game packet fields
|
||||||
|
in 10..13 -> "Game Length (ms)"
|
||||||
|
in 14..17 -> "Time till Countdown (ms)"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
0x02.toByte() -> when (index) { // Event packet fields
|
||||||
|
in 10..15 -> "Target Address"
|
||||||
|
in 16..19 -> "Event ID"
|
||||||
|
in 20..23 -> "Event Data"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
0x03.toByte() -> when (index) { // Tag packet fields
|
||||||
|
10 -> "Tx Pwr (dBm)"
|
||||||
|
11 -> "Protocol"
|
||||||
|
12 -> "Team ID"
|
||||||
|
13 -> "Player ID"
|
||||||
|
14, 15 -> "Damage"
|
||||||
|
in 16..19 -> "Color"
|
||||||
|
in 20..25 -> "Target Address"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
0x04.toByte() -> when (index) { // Console packet fields
|
||||||
|
in 10..30 -> "Console String"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
0x05.toByte() -> when (index) { // Status packet fields
|
||||||
|
10 -> "Tx Pwr (dBm)"
|
||||||
|
11 -> "Protocol"
|
||||||
|
12 -> "Team ID"
|
||||||
|
13 -> "Player ID"
|
||||||
|
14, 15 -> "Health"
|
||||||
|
16, 17 -> "Max Health"
|
||||||
|
in 18..21 -> "Primary Color"
|
||||||
|
in 22..25 -> "Secondary Color"
|
||||||
|
26 -> "SystemK State"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
0x06.toByte() -> when (index) { // Configuration packet fields
|
||||||
|
in 10..15 -> "Target Address"
|
||||||
|
16 -> "Subtype"
|
||||||
|
17, 18 -> "Key 1"
|
||||||
|
in 19..22 -> "Value 1"
|
||||||
|
23, 24 -> "Key 2"
|
||||||
|
in 25..28 -> "Value 2"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
0x07.toByte() -> when (index) { // Hello packet fields
|
||||||
|
10 -> "SystemK Major Version"
|
||||||
|
11 -> "SystemK Minor Version"
|
||||||
|
12, 13 -> "Device Type"
|
||||||
|
14 -> "Team ID"
|
||||||
|
in 15..30 -> "Device Name"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFieldColor(packetType: Byte, index: Int): Color? {
|
||||||
|
// Header bytes always return null to use default header color
|
||||||
|
if (index < 8) return null
|
||||||
|
|
||||||
|
// Packet type byte is always a distinct color
|
||||||
|
if (index == 8) return Color(0xFFE6F3FF) // Light blue
|
||||||
|
|
||||||
|
// Event number is always the same color across all packet types
|
||||||
|
if (index == 9) return Color(0xFFE6FFE6) // Light green
|
||||||
|
|
||||||
|
return when (packetType) {
|
||||||
|
0x01.toByte() -> when (index) { // Instigate Game packet
|
||||||
|
in 10..13 -> Color(0xFFFFF3E6) // Game Length - Light orange
|
||||||
|
in 14..17 -> Color(0xFFE6FFF3) // Time until Countdown - Light cyan
|
||||||
|
else -> Color(0xFFF5F5F5) // Light gray for undefined fields
|
||||||
|
}
|
||||||
|
|
||||||
|
0x02.toByte() -> when (index) { // Event packet
|
||||||
|
in 10..15 -> Color(0xFFE6F3FF) // Target Address - Light blue
|
||||||
|
in 16..19 -> Color(0xFFF3E6FF) // Event ID - Light purple
|
||||||
|
in 20..23 -> Color(0xFFE6FFE6) // Event Data - Light green
|
||||||
|
else -> Color(0xFFF5F5F5) // Light gray for undefined fields
|
||||||
|
}
|
||||||
|
|
||||||
|
0x03.toByte() -> when (index) { // Tag packet
|
||||||
|
10 -> Color(0xFFFFF3E6) // Tx Power - Light orange
|
||||||
|
11 -> Color(0xFFE6FFF3) // Protocol - Light cyan
|
||||||
|
12 -> Color(0xFFFFE6F3) // Team ID - Light pink
|
||||||
|
13 -> Color(0xFFF3E6FF) // Player ID - Light purple
|
||||||
|
in 14..15 -> Color(0xFFFFE6E6) // Damage - Light red
|
||||||
|
in 16..19 -> Color(0xFFE6FFE6) // Color - Light green
|
||||||
|
in 20..25 -> Color(0xFFE6F3FF) // Target Address - Light blue
|
||||||
|
else -> Color(0xFFF5F5F5) // Light gray for undefined fields
|
||||||
|
}
|
||||||
|
|
||||||
|
0x04.toByte() -> when (index) { // Console packet
|
||||||
|
in 10..30 -> Color(0xFFFFF3E6) // Console String - Light orange
|
||||||
|
else -> Color(0xFFF5F5F5) // Light gray for undefined fields
|
||||||
|
}
|
||||||
|
|
||||||
|
0x05.toByte() -> when (index) { // Status packet
|
||||||
|
10 -> Color(0xFFFFF3E6) // Tx Power - Light orange
|
||||||
|
11 -> Color(0xFFE6FFF3) // Protocol - Light cyan
|
||||||
|
12 -> Color(0xFFFFE6F3) // Team ID - Light pink
|
||||||
|
13 -> Color(0xFFF3E6FF) // Player ID - Light purple
|
||||||
|
14, 15 -> Color(0xFFFFE6E6) // Health - Light red
|
||||||
|
16, 17 -> Color(0xFFE6FFE6) // Maximum Health - Light green
|
||||||
|
in 18..21 -> Color(0xFFE6F3FF) // Primary Color - Light blue
|
||||||
|
in 22..25 -> Color(0xFFF3E6FF) // Secondary Color - Light purple
|
||||||
|
26 -> Color(0xFFFFF3E6) // SystemK State - Light orange
|
||||||
|
else -> Color(0xFFF5F5F5) // Light gray for undefined fields
|
||||||
|
}
|
||||||
|
|
||||||
|
0x06.toByte() -> when (index) { // Configuration packet
|
||||||
|
in 10..15 -> Color(0xFFE6F3FF) // Target Address - Light blue
|
||||||
|
16 -> Color(0xFFFFF3E6) // Subtype - Light orange
|
||||||
|
17, 18 -> Color(0xFFF3E6FF) // Key 1 - Light purple
|
||||||
|
in 19..22 -> Color(0xFFE6FFE6) // Value 1 - Light green
|
||||||
|
23, 24 -> Color(0xFFF3E6FF) // Key 2 - Light purple
|
||||||
|
in 25..28 -> Color(0xFFE6FFE6) // Value 2 - Light green
|
||||||
|
else -> Color(0xFFF5F5F5) // Light gray for undefined fields
|
||||||
|
}
|
||||||
|
|
||||||
|
0x07.toByte() -> when (index) { // Hello packet
|
||||||
|
10 -> Color(0xFFFFF3E6) // SystemK Major Version - Light orange
|
||||||
|
11 -> Color(0xFFE6FFF3) // SystemK Minor Version - Light cyan
|
||||||
|
12, 13 -> Color(0xFFE6F3FF) // Device Type - Light blue
|
||||||
|
14 -> Color(0xFFFFE6F3) // Team ID - Light pink
|
||||||
|
in 15..30 -> Color(0xFFF3E6FF) // Device Name - Light purple
|
||||||
|
else -> Color(0xFFF5F5F5) // Light gray for undefined fields
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> Color(0xFFF5F5F5) // Light gray for unknown packet types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue