Implemented all seven packet types.

This commit is contained in:
Joe Kearney 2025-02-09 17:42:21 -06:00
parent bc6da05747
commit c9704c4bf4
3 changed files with 240 additions and 71 deletions

View file

@ -1,7 +1,10 @@
package club.clubk.ktag.bletool
import androidx.compose.ui.graphics.Color
data class ByteCellData(
val value: Byte,
val isHeader: Boolean,
val description: String
val description: String,
val backgroundColor: Color? = null
)

View file

@ -15,12 +15,15 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
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.style.TextAlign
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.core.content.ContextCompat
private const val TAG = "BLE Tool"
@ -95,7 +94,7 @@ val advertisementPresets = listOf(
0x00.toByte(),
0x00.toByte(), // Event Data
),
"KTag Instigate Game Packet"
"KTag Event Packet"
),
AdvertisementPreset(
"03 Tag",
@ -146,10 +145,64 @@ val advertisementPresets = listOf(
),
"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(
"Empty",
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
val byteCells = remember(advertisementData) {
val packetType = advertisementData[8]
advertisementData.mapIndexed { index, byte ->
ByteCellData(
value = byte, isHeader = index < N_HEADER_BYTES, description = 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'"
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 -> ""
}
}
}
}
value = byte,
isHeader = index < N_HEADER_BYTES,
description = PacketFieldUtils.getFieldDescription(packetType, index),
backgroundColor = PacketFieldUtils.getFieldColor(packetType, index)
)
}
}
@ -556,6 +551,7 @@ fun ByteCell(
val backgroundColor = when {
data.isHeader -> MaterialTheme.colorScheme.secondaryContainer
isSelected -> MaterialTheme.colorScheme.primary
data.backgroundColor != null -> data.backgroundColor
else -> MaterialTheme.colorScheme.primaryContainer
}

View 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
}
}
}