From 5bd5fc3f740a7c94ee673e956a881d83bf361615 Mon Sep 17 00:00:00 2001 From: Christopher O'Grady Date: Sat, 4 Jan 2025 23:03:01 -0500 Subject: [PATCH] Use nfc library from maven local instead of copied module. --- app/build.gradle.kts | 2 +- gradle/libs.versions.toml | 2 + settings.gradle.kts | 2 +- vb-nfc-reader/.gitignore | 1 - vb-nfc-reader/.idea/.gitignore | 3 - .../.idea/caches/deviceStreaming.xml | 340 ------------------ vb-nfc-reader/.idea/gradle.xml | 13 - vb-nfc-reader/.idea/misc.xml | 9 - vb-nfc-reader/.idea/runConfigurations.xml | 17 - vb-nfc-reader/build.gradle.kts | 44 --- vb-nfc-reader/consumer-rules.pro | 0 vb-nfc-reader/proguard-rules.pro | 21 -- .../cfogrady/vbnfc/ExampleInstrumentedTest.kt | 24 -- vb-nfc-reader/src/main/AndroidManifest.xml | 4 - .../github/cfogrady/vbnfc/ByteManipulation.kt | 78 ---- .../cfogrady/vbnfc/ChecksumCalculator.kt | 41 --- .../vbnfc/CryptographicTransformer.kt | 110 ------ .../cfogrady/vbnfc/NfcDataTranslator.kt | 30 -- .../vbnfc/NfcDataTranslatorFactory.kt | 22 -- .../github/cfogrady/vbnfc/TagCommunicator.kt | 193 ---------- .../java/com/github/cfogrady/vbnfc/Utils.kt | 20 -- .../cfogrady/vbnfc/be/BENfcCharacter.kt | 183 ---------- .../cfogrady/vbnfc/be/BENfcDataFactory.kt | 68 ---- .../cfogrady/vbnfc/be/BENfcDataTranslator.kt | 271 -------------- .../github/cfogrady/vbnfc/be/BENfcDevice.kt | 20 -- .../cfogrady/vbnfc/be/FirmwareVersion.kt | 3 - .../cfogrady/vbnfc/data/DeviceSubType.kt | 12 - .../github/cfogrady/vbnfc/data/DeviceType.kt | 9 - .../cfogrady/vbnfc/data/NfcCharacter.kt | 147 -------- .../com/github/cfogrady/vbnfc/data/NfcData.kt | 3 - .../github/cfogrady/vbnfc/data/NfcDevice.kt | 9 - .../github/cfogrady/vbnfc/data/NfcHeader.kt | 26 -- .../cfogrady/vbnfc/vb/VBNfcDataTranslator.kt | 45 --- .../github/cfogrady/vbnfc/vb/VBNfcHeader.kt | 25 -- vb-nfc-reader/src/main/res/values/arrays.xml | 4 - vb-nfc-reader/src/main/res/values/strings.xml | 6 - .../vbnfc/CryptographicTransformerHelper.kt | 50 --- .../vbnfc/CryptographicTransformerTest.kt | 56 --- .../vbnfc/be/BENfcDataTranslatorTest.kt | 73 ---- 39 files changed, 4 insertions(+), 1982 deletions(-) delete mode 100644 vb-nfc-reader/.gitignore delete mode 100644 vb-nfc-reader/.idea/.gitignore delete mode 100644 vb-nfc-reader/.idea/caches/deviceStreaming.xml delete mode 100644 vb-nfc-reader/.idea/gradle.xml delete mode 100644 vb-nfc-reader/.idea/misc.xml delete mode 100644 vb-nfc-reader/.idea/runConfigurations.xml delete mode 100644 vb-nfc-reader/build.gradle.kts delete mode 100644 vb-nfc-reader/consumer-rules.pro delete mode 100644 vb-nfc-reader/proguard-rules.pro delete mode 100644 vb-nfc-reader/src/androidTest/java/com/github/cfogrady/vbnfc/ExampleInstrumentedTest.kt delete mode 100644 vb-nfc-reader/src/main/AndroidManifest.xml delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/ByteManipulation.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/ChecksumCalculator.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/CryptographicTransformer.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/NfcDataTranslator.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/NfcDataTranslatorFactory.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/TagCommunicator.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/Utils.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcCharacter.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDataFactory.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDataTranslator.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDevice.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/FirmwareVersion.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/DeviceSubType.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/DeviceType.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcCharacter.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcData.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcDevice.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcHeader.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/vb/VBNfcDataTranslator.kt delete mode 100644 vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/vb/VBNfcHeader.kt delete mode 100644 vb-nfc-reader/src/main/res/values/arrays.xml delete mode 100644 vb-nfc-reader/src/main/res/values/strings.xml delete mode 100644 vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/CryptographicTransformerHelper.kt delete mode 100644 vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/CryptographicTransformerTest.kt delete mode 100644 vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/be/BENfcDataTranslatorTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 814ed65..c5ff661 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -42,7 +42,7 @@ android { dependencies { implementation(libs.androidx.room.runtime) - implementation(project(":vb-nfc-reader")) + implementation(libs.vb.nfc.reader) ksp(libs.androidx.room.compiler) annotationProcessor(libs.androidx.room.compiler) implementation(libs.androidx.core.ktx) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 76b8854..f88a17a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ lifecycleRuntimeKtx = "2.8.7" activityCompose = "1.9.3" composeBom = "2024.04.01" roomRuntime = "2.6.1" +vbNfcReader = "0.1.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -27,6 +28,7 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +vb-nfc-reader = { module = "com.github.cfogrady:vb-nfc-reader", version.ref = "vbNfcReader" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } diff --git a/settings.gradle.kts b/settings.gradle.kts index aa3e0ce..917b611 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,6 +14,7 @@ pluginManagement { dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { + mavenLocal() google() mavenCentral() } @@ -21,4 +22,3 @@ dependencyResolutionManagement { rootProject.name = "VBHelper" include(":app") -include(":vb-nfc-reader") diff --git a/vb-nfc-reader/.gitignore b/vb-nfc-reader/.gitignore deleted file mode 100644 index 42afabf..0000000 --- a/vb-nfc-reader/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/vb-nfc-reader/.idea/.gitignore b/vb-nfc-reader/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/vb-nfc-reader/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/vb-nfc-reader/.idea/caches/deviceStreaming.xml b/vb-nfc-reader/.idea/caches/deviceStreaming.xml deleted file mode 100644 index 406736c..0000000 --- a/vb-nfc-reader/.idea/caches/deviceStreaming.xml +++ /dev/null @@ -1,340 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/vb-nfc-reader/.idea/gradle.xml b/vb-nfc-reader/.idea/gradle.xml deleted file mode 100644 index d3f0572..0000000 --- a/vb-nfc-reader/.idea/gradle.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/vb-nfc-reader/.idea/misc.xml b/vb-nfc-reader/.idea/misc.xml deleted file mode 100644 index 8bb1dd1..0000000 --- a/vb-nfc-reader/.idea/misc.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/vb-nfc-reader/.idea/runConfigurations.xml b/vb-nfc-reader/.idea/runConfigurations.xml deleted file mode 100644 index 16660f1..0000000 --- a/vb-nfc-reader/.idea/runConfigurations.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/vb-nfc-reader/build.gradle.kts b/vb-nfc-reader/build.gradle.kts deleted file mode 100644 index c9539df..0000000 --- a/vb-nfc-reader/build.gradle.kts +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - id("com.android.library") - id("org.jetbrains.kotlin.android") -} - -android { - namespace = "com.github.cfogrady.vbnfc" - compileSdk = 34 - - defaultConfig { - minSdk = 28 - - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles("consumer-rules.pro") - } - - buildTypes { - release { - isMinifyEnabled = false - proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), - "proguard-rules.pro" - ) - } - } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } -} - -dependencies { - implementation("androidx.core:core-ktx:1.12.0") - implementation("androidx.appcompat:appcompat:1.6.1") - implementation("com.google.android.material:material:1.11.0") - testImplementation("junit:junit:4.13.2") - androidTestImplementation("androidx.test.ext:junit:1.1.5") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") - testImplementation("io.mockk:mockk-android:1.13.14") - testImplementation("io.mockk:mockk-agent:1.13.14") -} \ No newline at end of file diff --git a/vb-nfc-reader/consumer-rules.pro b/vb-nfc-reader/consumer-rules.pro deleted file mode 100644 index e69de29..0000000 diff --git a/vb-nfc-reader/proguard-rules.pro b/vb-nfc-reader/proguard-rules.pro deleted file mode 100644 index 481bb43..0000000 --- a/vb-nfc-reader/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/vb-nfc-reader/src/androidTest/java/com/github/cfogrady/vbnfc/ExampleInstrumentedTest.kt b/vb-nfc-reader/src/androidTest/java/com/github/cfogrady/vbnfc/ExampleInstrumentedTest.kt deleted file mode 100644 index 21ef40e..0000000 --- a/vb-nfc-reader/src/androidTest/java/com/github/cfogrady/vbnfc/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.github.cfogrady.vbnfc - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.github.cfogrady.vbnfc.test", appContext.packageName) - } -} \ No newline at end of file diff --git a/vb-nfc-reader/src/main/AndroidManifest.xml b/vb-nfc-reader/src/main/AndroidManifest.xml deleted file mode 100644 index a5918e6..0000000 --- a/vb-nfc-reader/src/main/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/ByteManipulation.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/ByteManipulation.kt deleted file mode 100644 index f7514eb..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/ByteManipulation.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.github.cfogrady.vbnfc - -import java.lang.IllegalArgumentException -import java.nio.ByteOrder - -fun ByteArray.getUInt32(index: Int = 0, byteOrder: ByteOrder = ByteOrder.nativeOrder()): UInt { - if (this.size < index + 4) { - throw IllegalArgumentException("Must be 4 bytes from index to get a UInt") - } - var result: UInt = 0u - for (i in 0 until 4) { - result = if (byteOrder == ByteOrder.BIG_ENDIAN) { - result or ((this[index+i].toUInt() and 0xFFu) shl 8*(3 - i)) - } else { - result or ((this[index+i].toUInt() and 0xFFu) shl 8*(i)) - } - } - return result -} - -fun UInt.toByteArray(byteOrder: ByteOrder = ByteOrder.nativeOrder()): ByteArray { - val byteArray = byteArrayOf(0, 0, 0, 0) - for(i in 0 until 4) { - if(byteOrder == ByteOrder.LITTLE_ENDIAN) { - byteArray[i] = ((this shr 8*i) and 255u).toByte() - } else { - byteArray[3-i] = ((this shr 8*i) and 255u).toByte() - } - } - return byteArray -} - -fun ByteArray.getUInt16(index: Int = 0, byteOrder: ByteOrder = ByteOrder.nativeOrder()): UShort { - if (this.size < index + 2) { - throw IllegalArgumentException("Must be 2 bytes from index to get a UInt") - } - var result: UInt = 0u - for (i in 0 until 2) { - result = if (byteOrder == ByteOrder.BIG_ENDIAN) { - result or ((this[index+i].toUInt() and 0xFFu) shl 8*(1 - i)) - } else { - result or ((this[index+i].toUInt() and 0xFFu) shl 8*(i)) - } - } - return result.toUShort() -} - -fun UShort.toByteArray(byteOrder: ByteOrder = ByteOrder.nativeOrder()): ByteArray { - val byteArray = byteArrayOf(0, 0) - val asUInt = this.toUInt() - for(i in 0 until 2) { - if(byteOrder == ByteOrder.LITTLE_ENDIAN) { - byteArray[i] = ((asUInt shr 8*i) and 255u).toByte() - } else { - byteArray[1-i] = ((asUInt shr 8*i) and 255u).toByte() - } - } - return byteArray -} - -fun UShort.toByteArray(bytes: ByteArray, dstIndex: Int, byteOrder: ByteOrder = ByteOrder.nativeOrder()) { - val asUInt = this.toUInt() - for(i in 0 until 2) { - if(byteOrder == ByteOrder.LITTLE_ENDIAN) { - bytes[i+dstIndex] = ((asUInt shr 8*i) and 255u).toByte() - } else { - bytes[(1-i) + dstIndex] = ((asUInt shr 8*i) and 255u).toByte() - } - } -} - -fun ByteArray.copyIntoUShortArray(offset: Int, length: Int): Array { - val result = Array(length) { 0u } - for (i in 0.. - if (checksumByte != data[checksumIdx]) { - throw IllegalStateException("Checksum ${checksumByte.toHexString()} doesn't match expected ${data[checksumIdx].toHexString()}") - } - } - } - - @OptIn(ExperimentalStdlibApi::class) - fun recalculateChecksums(data: ByteArray) { - operateOnChecksums(data) { checksumByte, checksumIdx -> - data[checksumIdx] = checksumByte - } - } - - private fun operateOnChecksums(data: ByteArray, operator: (Byte, Int)->Unit) { - // loop through all data - for(i in data.indices step 16) { - val page = i/4 + 8 // first 8 pages are header data and not part of the character data - if (PagesWithChecksum.contains(page)) { - var sum = 0 - val checksumIndex = i + 15 - for(j in i.. = HashMap() -) { - - - fun getNfcDataTranslator(deviceTypeId: UShort): NfcDataTranslator { - val dataTranslator = translators[deviceTypeId] - if(dataTranslator != null) { - return dataTranslator - } - throw UnsupportedOperationException("Device type ${deviceTypeId} is not yet supported") - } - - fun addNfcDataTranslator(nfcDataTranslator: NfcDataTranslator, deviceTypeId: UShort) { - translators[deviceTypeId] = nfcDataTranslator - } -} \ No newline at end of file diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/TagCommunicator.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/TagCommunicator.kt deleted file mode 100644 index 51c6ae9..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/TagCommunicator.kt +++ /dev/null @@ -1,193 +0,0 @@ -package com.github.cfogrady.vbnfc - -import android.nfc.tech.NfcA -import android.util.Log -import com.github.cfogrady.vbnfc.be.BENfcDataTranslator -import com.github.cfogrady.vbnfc.data.DeviceType -import com.github.cfogrady.vbnfc.data.NfcCharacter -import com.github.cfogrady.vbnfc.data.NfcHeader -import java.nio.ByteOrder - -class TagCommunicator( - private val nfcData: NfcA, - private val checksumCalculator: ChecksumCalculator, - private val nfcDataTranslatorFactory: NfcDataTranslatorFactory, - ) { - - companion object { - const val TAG = "VBNfcHandler" - const val HEADER_PAGE: Byte = 0x04 - const val NFC_PASSWORD_COMMAND: Byte = 0x1b - const val NFC_READ_COMMAND: Byte = 0x30 - const val NFC_WRITE_COMMAND: Byte = 0xA2.toByte() - - const val STATUS_IDLE: Byte = 0 - const val STATUS_READY: Byte = 1 - - const val OPERATION_IDLE: Byte = 0 - const val OPERATION_READY: Byte = 1 - const val OPERATION_TRANSFERRED_TO_APP: Byte = 2 - const val OPERATION_CHECK_DIM: Byte = 3 - const val OPERATION_TRANSFERED_TO_DEVICE: Byte = 4 - const val START_DATA_PAGE = 8 - const val LAST_DATA_PAGE = 220 // technically 223, but we read 4 pages at a time. - - fun getInstance(nfcData: NfcA, deviceTypeIdSecrets: Map): TagCommunicator { - val checksumCalculator = ChecksumCalculator() - val deviceToTranslator = HashMap() - for (keyValue in deviceTypeIdSecrets) { - when(keyValue.key) { - DeviceType.VitalBraceletBEDeviceType -> { - deviceToTranslator[keyValue.key] = BENfcDataTranslator(keyValue.value, checksumCalculator) - } - else -> { - throw IllegalArgumentException("DeviceId ${keyValue.key} Provided Without Known Parser") - } - } - } - return TagCommunicator(nfcData, checksumCalculator, NfcDataTranslatorFactory(deviceToTranslator)) - } - - } - - data class DeviceTranslatorAndHeader(val nfcHeader: NfcHeader, val translator: NfcDataTranslator) - - @OptIn(ExperimentalStdlibApi::class) - fun receiveCharacter(): NfcCharacter { - val translatorAndHeader = fetchDeviceTranslatorAndHeader() - val header = translatorAndHeader.nfcHeader - val translator = translatorAndHeader.translator - Log.i(TAG, "Writing to make ready for operation") - nfcData.transceive(translator.getOperationCommandBytes(header, OPERATION_READY)) - Log.i(TAG, "Authenticating") - - passwordAuth(translator.cryptographicTransformer) - Log.i(TAG, "Reading Character") - val encryptedCharacterData = readNfcData() - Log.i(TAG, "Raw NFC Data Received: ${encryptedCharacterData.toHexString()}") - val decryptedCharacterData = translator.cryptographicTransformer.decryptData(encryptedCharacterData, nfcData.tag.id) - checksumCalculator.checkChecksums(decryptedCharacterData) - val nfcCharacter = translator.parseNfcCharacter(decryptedCharacterData) - Log.i(TAG, "Known Character Stats: $nfcCharacter") - // Not ready to lose any of my mons in this... - //Log.i(TAG, "Signaling operation complete") - //nfcData.transceive(translator.getOperationCommandBytes(header, OPERATION_TRANSFERRED_TO_APP)) - return nfcCharacter - } - - @OptIn(ExperimentalStdlibApi::class) - private fun fetchDeviceTranslatorAndHeader(): DeviceTranslatorAndHeader { - val readData = nfcData.transceive(byteArrayOf(NFC_READ_COMMAND, HEADER_PAGE)) - Log.i("TagCommunicator", "First 4 Pages: ${readData.toHexString()}") - val deviceTypeId = readData.getUInt16(4, ByteOrder.BIG_ENDIAN) - val translator = nfcDataTranslatorFactory.getNfcDataTranslator(deviceTypeId) - val header = translator.parseHeader(readData) - return DeviceTranslatorAndHeader(header, translator) - } - - private fun readNfcData(): ByteArray { - val result = ByteArray(((LAST_DATA_PAGE +4)- START_DATA_PAGE) * 4) - for (page in START_DATA_PAGE..LAST_DATA_PAGE step 4) { - val pages = nfcData.transceive(byteArrayOf(NFC_READ_COMMAND, page.toByte())) - if (pages.size < 16) { - throw Exception("Failed to read page: $page") - } - System.arraycopy(pages, 0, result, (page - START_DATA_PAGE)*4, pages.size) - } - return result - } - - fun prepareDIMForCharacter(dimId: UShort) { - val translatorAndHeader = fetchDeviceTranslatorAndHeader() - val header = translatorAndHeader.nfcHeader - val translator = translatorAndHeader.translator - // set app nonce to device ensure when we send back the character that we are preparing - // the same device we send to - nfcData.transceive(translator.getOperationCommandBytes(header, OPERATION_READY)) - // app authenticates, and reads everything, and checks the version - // The version check is only for the BE when transfering from DIM=0 (pulsemon). - // This was from the bug when the BE first came out. - // Check (page 103 [0:1] != 1, 0) - header.setDimId(dimId) - nfcData.transceive(translator.getOperationCommandBytes(header, OPERATION_CHECK_DIM)) - } - - private fun defaultNfcDataGenerator(translator: NfcDataTranslator, character: NfcCharacter): ByteArray { - val currentNfcData = readNfcData() - val newNfcData = translator.cryptographicTransformer.decryptData(currentNfcData, nfcData.tag.id) - translator.setCharacterInByteArray(character, newNfcData) - checksumCalculator.recalculateChecksums(newNfcData) - translator.finalizeByteArrayFormat(newNfcData) - return newNfcData - } - - // sendCharacter sends a character to the device using the nfcDataGenerator function. The - // default nfcDataGenerator reads the current data of the device and applies the new character - // data to the read data and prepares that to be sent back to the device. The nfcDataGenerator - // is a functor which takes in the NfcDataTranslator for the device and the NfcCharacter - // provided to the sendCharacter method and returns the decrypted byte array data to be sent - // back to the device. - @OptIn(ExperimentalStdlibApi::class) - fun sendCharacter(character: NfcCharacter, nfcDataGenerator: (NfcDataTranslator, NfcCharacter) -> ByteArray = this::defaultNfcDataGenerator) { - Log.i(TAG, "Sending Character: $character") - val deviceTranslatorAndHeader = fetchDeviceTranslatorAndHeader() - val translator = deviceTranslatorAndHeader.translator - val header = deviceTranslatorAndHeader.nfcHeader - - // check the nonce - // if it's not expected, then the bracelet isn't ready - - // Check the product and device ids that they match the target. - // This check relies on the app categories of BE, Vital Hero, and Vital Series. - - // ensure the dim id matches the expected - if (character.dimId != header.getDimId()) { - throw IllegalArgumentException("Device is ready for DIM ${header.getDimId()}, but attempted to send ${character.dimId}") - } - - // update the memory data - nfcData.transceive(translator.getOperationCommandBytes(header, OPERATION_READY)) - passwordAuth(translator.cryptographicTransformer) - - var newNfcData = nfcDataGenerator(translator, character) - newNfcData = translator.cryptographicTransformer.encryptData(newNfcData, nfcData.tag.id) - Log.i(TAG, "Sending Character: ${newNfcData.toHexString()}") - - - // write nfc data - val pagedData = ConvertToPages(newNfcData) - for(pageToWriteIdx in 8.. { - val pages = ArrayList() - // setup blank header pages - for (i in 0..7) { - if (header != null) { - val index = i*4 - pages.add(header.sliceArray(index.., - var trainingHp: UShort, - var trainingAp: UShort, - var trainingBp: UShort, - var remainingTrainingTimeInMinutes: UShort, - var itemEffectMentalStateValue: Byte, - var itemEffectMentalStateMinutesRemaining: Byte, - var itemEffectActivityLevelValue: Byte, - var itemEffectActivityLevelMinutesRemaining: Byte, - var itemEffectVitalPointsChangeValue: Byte, - var itemEffectVitalPointsChangeMinutesRemaining: Byte, - var abilityRarity: AbilityRarity, - var abilityType: UShort, - var abilityBranch: UShort, - var abilityReset: Byte, - var rank: Byte, - var itemType: Byte, - var itemMultiplier: Byte, - var itemRemainingTime: Byte, - internal val otp0: ByteArray, // OTP matches the character to the dim - internal val otp1: ByteArray, // OTP matches the character to the dim - var characterCreationFirmwareVersion: FirmwareVersion, - var appReserved1: ByteArray, // this is a 12 byte array reserved for new app features, a custom app should be able to safely use this for custom features - var appReserved2: Array, // this is a 3 element array reserved for new app features, a custom app should be able to safely use this for custom features -) : - NfcCharacter( - dimId = dimId, - charIndex = charIndex, - stage = stage, - attribute = attribute, - ageInDays = ageInDays, - nextAdventureMissionStage = nextAdventureMissionStage, - mood = mood, - vitalPoints = vitalPoints, - transformationCountdown = transformationCountdownInMinutes, - injuryStatus = injuryStatus, - trophies = trainingPp, - currentPhaseBattlesWon = currentPhaseBattlesWon, - currentPhaseBattlesLost = currentPhaseBattlesLost, - totalBattlesWon = totalBattlesWon, - totalBattlesLost = totalBattlesLost, - activityLevel = activityLevel, - heartRateCurrent = heartRateCurrent, - transformationHistory = transformationHistory, - ) -{ - fun getTrainingPp(): UShort { - return trophies - } - - fun setTrainingPp(trainingPp: UShort) { - trophies = trainingPp - } - - fun getWinPercentage(): Byte { - val totalBatles = currentPhaseBattlesWon + currentPhaseBattlesLost - if (totalBatles == 0u) { - return 0 - } - return ((100u * currentPhaseBattlesWon) / totalBatles).toByte() - } - - - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as BENfcCharacter - if(!super.equals(other)) return false - - if (trainingHp != other.trainingHp) return false - if (trainingAp != other.trainingAp) return false - if (trainingBp != other.trainingBp) return false - if (remainingTrainingTimeInMinutes != other.remainingTrainingTimeInMinutes) return false - if (itemEffectMentalStateValue != other.itemEffectMentalStateValue) return false - if (itemEffectMentalStateMinutesRemaining != other.itemEffectMentalStateMinutesRemaining) return false - if (itemEffectActivityLevelValue != other.itemEffectActivityLevelValue) return false - if (itemEffectActivityLevelMinutesRemaining != other.itemEffectActivityLevelMinutesRemaining) return false - if (itemEffectVitalPointsChangeValue != other.itemEffectVitalPointsChangeValue) return false - if (itemEffectVitalPointsChangeMinutesRemaining != other.itemEffectVitalPointsChangeMinutesRemaining) return false - if (abilityRarity != other.abilityRarity) return false - if (abilityType != other.abilityType) return false - if (abilityBranch != other.abilityBranch) return false - if (abilityReset != other.abilityReset) return false - if (rank != other.rank) return false - if (itemType != other.itemType) return false - if (itemMultiplier != other.itemMultiplier) return false - if (itemRemainingTime != other.itemRemainingTime) return false - if (!otp0.contentEquals(other.otp0)) return false - if (!otp1.contentEquals(other.otp1)) return false - if (characterCreationFirmwareVersion != other.characterCreationFirmwareVersion) return false - if (!appReserved1.contentEquals(other.appReserved1)) return false - if (!appReserved2.contentEquals(other.appReserved2)) return false - - return true - } - - override fun hashCode(): Int { - return Objects.hash( - super.hashCode(), - trainingHp, - trainingAp, - trainingBp, - remainingTrainingTimeInMinutes, - itemEffectMentalStateValue, - itemEffectMentalStateMinutesRemaining, - itemEffectActivityLevelValue, - itemEffectActivityLevelMinutesRemaining, - itemEffectVitalPointsChangeValue, - itemEffectVitalPointsChangeMinutesRemaining, - abilityRarity, - abilityType, - abilityBranch, - abilityReset, - rank, - itemType, - itemMultiplier, - itemRemainingTime, - otp0.contentHashCode(), - otp1.contentHashCode(), - characterCreationFirmwareVersion, - appReserved1.contentHashCode(), - appReserved2.contentHashCode()) - } - - @OptIn(ExperimentalStdlibApi::class) - override fun toString(): String { - return """ -${super.toString()} -BENfcCharacter( - trainingHp=$trainingHp, - trainingAp=$trainingAp, - trainingBp=$trainingBp, - remainingTrainingTimeInMinutes=$remainingTrainingTimeInMinutes, - itemEffectMentalStateValue=$itemEffectMentalStateValue, - itemEffectMentalStateMinutesRemaining=$itemEffectMentalStateMinutesRemaining, - itemEffectActivityLevelValue=$itemEffectActivityLevelValue, - itemEffectActivityLevelMinutesRemaining=$itemEffectActivityLevelMinutesRemaining, - itemEffectVitalPointsChangeValue=$itemEffectVitalPointsChangeValue, - itemEffectVitalPointsChangeMinutesRemaining=$itemEffectVitalPointsChangeMinutesRemaining, - abilityRarity=$abilityRarity, - abilityType=$abilityType, - abilityBranch=$abilityBranch, - abilityReset=$abilityReset, - rank=$rank, - itemType=$itemType, - itemMultiplier=$itemMultiplier, - itemRemainingTime=$itemRemainingTime, - otp0=${otp0.toHexString()}, - otp1=${otp1.toHexString()}, - characterCreationFirmwareVersion=$characterCreationFirmwareVersion, - appReserved1=${appReserved1.contentToString()}, - appReserved2=${appReserved2.contentToString()} -)""" - } - - -} diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDataFactory.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDataFactory.kt deleted file mode 100644 index 2fc6608..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDataFactory.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.github.cfogrady.vbnfc.be - -import com.github.cfogrady.vbnfc.ChecksumCalculator - -// Obsolete... being held onto for reference to device side data. -class BENfcDataFactory(checksumCalculator: ChecksumCalculator = ChecksumCalculator()) { - - - - fun buildBENfcDevice(bytes: ByteArray): BENfcDevice { - return BENfcDevice( - gender = BENfcDevice.Gender.entries[bytes[12].toInt()], - registedDims = bytes.sliceArray(32..<32+15), - currDays = bytes[78] - ) - - - -// reserved1 = readByte(107) -// saveFirmwareVersion = readUShort(108) -// advMissionStage = readByte(128) -// -// -// -// -// reserved2 = readByte(140) -// -// reserved3 = readUShort(162) -// year = readByte(164) -// month = readByte(165) -// day = readByte(166) -// vitalPointsHistory0 = readUShort(176) -// vitalPointsHistory1 = readUShort(178) -// vitalPointsHistory2 = readUShort(180) -// vitalPointsHistory3 = readUShort(182) -// vitalPointsHistory4 = readUShort(184) -// vitalPointsHistory5 = readUShort(186) -// year0PreviousVitalPoints = readByte(188) -// month0PreviousVitalPoints = readByte(189) -// day0PreviousVitalPoints = readByte(190) -// year1PreviousVitalPoints = readByte(192) -// month1PreviousVitalPoints = readByte(193) -// day1PreviousVitalPoints = readByte(194) -// year2PreviousVitalPoints = readByte(195) -// month2PreviousVitalPoints = readByte(196) -// day2PreviousVitalPoints = readByte(197) -// year3PreviousVitalPoints = readByte(198) -// month3PreviousVitalPoints = readByte(199) -// day3PreviousVitalPoints = readByte(200) -// year4PreviousVitalPoints = readByte(201) -// month4PreviousVitalPoints = readByte(202) -// day4PreviousVitalPoints = readByte(203) -// year5PreviousVitalPoints = readByte(204) -// month5PreviousVitalPoints = readByte(205) -// day5PreviousVitalPoints = readByte(206) -// -// reserved4 = readUShort(262) -// reserved5 = readByte(264) -// questionMark = readByte(265) -// reserved6 = readByte(289) -// reserved7 = readByte(291) -// -// reserved8 = readUShort(297) -// reserved9 = readUShortArray(376, 2) -// - } - -} \ No newline at end of file diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDataTranslator.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDataTranslator.kt deleted file mode 100644 index d0cd520..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDataTranslator.kt +++ /dev/null @@ -1,271 +0,0 @@ -package com.github.cfogrady.vbnfc.be - -import android.util.Log -import com.github.cfogrady.vbnfc.ChecksumCalculator -import com.github.cfogrady.vbnfc.CryptographicTransformer -import com.github.cfogrady.vbnfc.NfcDataTranslator -import com.github.cfogrady.vbnfc.TagCommunicator -import com.github.cfogrady.vbnfc.copyIntoUShortArray -import com.github.cfogrady.vbnfc.data.DeviceSubType -import com.github.cfogrady.vbnfc.data.DeviceType -import com.github.cfogrady.vbnfc.data.NfcCharacter -import com.github.cfogrady.vbnfc.data.NfcHeader -import com.github.cfogrady.vbnfc.getUInt16 -import com.github.cfogrady.vbnfc.toByteArray -import java.nio.ByteOrder - -class BENfcDataTranslator( - override val cryptographicTransformer: CryptographicTransformer, - private val checksumCalculator: ChecksumCalculator = ChecksumCalculator() -): NfcDataTranslator { - - companion object { - - const val OPERATION_PAGE: Byte = 0x6 - - // CHARACTER - const val APP_RESERVED_START = 0 - const val APP_RESERVED_SIZE = 12 - const val INJURY_STATUS_IDX = 64 - const val APP_RESERVED_2_START = 66 - const val APP_RESERVED_2_SIZE = 3 //3 ushorts - const val CHARACTER_INDEX_IDX = 72 - const val DIM_ID_IDX = 74 - const val PHASE_IDX = 76 - const val ATTRIBUTE_IDX = 77 - const val AGE_IN_DAYS_IDX = 78 // always 0 on BE :( - const val TRAINING_PP_IDX = 96 - const val CURRENT_BATTLES_WON_IDX = 98 - const val CURRENT_BATTLES_LOST_IDX = 100 - const val TOTAL_BATTLES_WON_IDX = 102 - const val TOTAL_BATTLES_LOST_IDX = 104 - const val WIN_PCT_IDX = 106 // unused - const val CHARACTER_CREATION_FIRMWARE_VERSION_IDX = 108 - const val NEXT_ADVENTURE_MISSION_STAGE_IDX = 128 - const val MOOD_IDX = 129 - const val ACTIVITY_LEVEL_IDX = 130 - const val HEART_RATE_CURRENT_IDX = 131 - const val VITAL_POINTS_IDX = 132 - const val ITEM_EFFECT_MENTAL_STATE_VALUE_IDX = 134 - const val ITEM_EFFECT_MENTAL_STATE_MINUTES_REMAINING_IDX = 135 - const val ITEM_EFFECT_ACTIVITY_LEVEL_VALUE_IDX = 136 - const val ITEM_EFFECT_ACTIVITY_LEVEL_MINUTES_REMAINING_IDX = 137 - const val ITEM_EFFECT_VITAL_POINTS_CHANGE_VALUE_IDX = 138 - const val ITEM_EFFECT_VITAL_POINTS_CHANGE_MINUTES_REMAINING_IDX = 139 - // 140 reserved - const val TRANSFORMATION_COUNT_DOWN_IDX = 141 - const val TRANSFORMATION_HISTORY_START = 208 - const val TRAINING_HP_IDX = 256 - const val TRAINING_AP_IDX = 258 - const val TRAINING_BP_IDX = 260 - const val TRAINING_TIME_IDX = 266 - const val RANK_IDX = 288 - const val ABILITY_RARITY_IDX = 290 - const val ABILITY_TYPE_IDX = 292 - const val ABILITY_BRANCH_IDX = 294 - const val ABILITY_RESET_IDX = 296 - const val ITEM_TYPE_IDX = 299 - const val ITEM_MULTIPLIER_IDX = 300 - const val ITEM_REMAINING_TIME_IDX = 301 - const val OTP_START_IDX = 352 - const val OTP_END_IDX = 359 - const val OTP2_START_IDX = 368 - const val OTP2_END_IDX = 375 - - // DEVICE - const val VITAL_POINTS_CURRENT_IDX = 160 - const val FIMRWARE_VERSION_IDX = 380 - - - } - - // setCharacterInByteArray takes the BENfcCharacter and modifies the byte array with character - // data. At the time of writing this is used to write a parsed character into fresh unparsed - // device data when sending a character back to the device. - override fun setCharacterInByteArray( - character: NfcCharacter, - bytes: ByteArray - ) { - val beCharacter = character as BENfcCharacter - beCharacter.appReserved1.copyInto(bytes, - APP_RESERVED_START, 0, - APP_RESERVED_SIZE - ) - beCharacter.injuryStatus.ordinal.toUShort().toByteArray(bytes, - INJURY_STATUS_IDX, ByteOrder.BIG_ENDIAN) - for(i in 0.., bytes: ByteArray) { - if (transformationHistory.size != 8) { - throw IllegalArgumentException("Transformation History must be exactly size 8") - } - for (phase in 0.. 2) { - rootIdx += 4 // we skip 220-223 for some reason - } - if (phase > 5) { - rootIdx += 4 // we skip 236-239 for some reason - } - bytes[rootIdx] = transformationHistory[phase].toCharIndex - bytes[rootIdx+1] = transformationHistory[phase].yearsSince1988 - bytes[rootIdx+2] = transformationHistory[phase].month - bytes[rootIdx+3] = transformationHistory[phase].day - } - } - - private fun buildTransformationHistory(data: ByteArray): Array { - val transformationHistory = Array(8) { phase -> - var rootIdx = phase*4 + TRANSFORMATION_HISTORY_START - if (phase > 2) { - rootIdx += 4 // we skip 220-223 for some reason - } - if (phase > 5) { - rootIdx += 4 // we skip 236-239 for some reason - } - NfcCharacter.Transformation( - toCharIndex = data[rootIdx], - yearsSince1988 = data[rootIdx+1], - month = data[rootIdx+2], - day = data[rootIdx+3] - ) - } - return transformationHistory - } -} \ No newline at end of file diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDevice.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDevice.kt deleted file mode 100644 index 29b2eba..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/BENfcDevice.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.github.cfogrady.vbnfc.be - -import com.github.cfogrady.vbnfc.data.NfcDevice -import java.util.BitSet - -class BENfcDevice( - val gender: Gender, - val registedDims: ByteArray, - val currDays: Byte, - - - ): - NfcDevice( - BitSet(), - ) { - enum class Gender { - Male, - Female - } -} \ No newline at end of file diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/FirmwareVersion.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/FirmwareVersion.kt deleted file mode 100644 index fb04c96..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/be/FirmwareVersion.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.github.cfogrady.vbnfc.be - -data class FirmwareVersion(val majorVersion: Byte, val minorVersion: Byte) \ No newline at end of file diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/DeviceSubType.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/DeviceSubType.kt deleted file mode 100644 index f0af04b..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/DeviceSubType.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.github.cfogrady.vbnfc.data - -class DeviceSubType { - companion object { - const val Original: UShort = 1u - const val FirstRevision: UShort = 2u - const val SecondRevision: UShort = 3u - const val DigiviceV: UShort = 4u - const val DigiviceVSecondRevision: UShort = 5u - const val VitalHero: UShort = 6u - } -} \ No newline at end of file diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/DeviceType.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/DeviceType.kt deleted file mode 100644 index 8e1e87a..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/DeviceType.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.cfogrady.vbnfc.data - -class DeviceType { - companion object { - const val VitalSeriesDeviceType: UShort = 2u - const val VitalCharactersDeviceType: UShort = 3u - const val VitalBraceletBEDeviceType: UShort = 4u - } -} diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcCharacter.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcCharacter.kt deleted file mode 100644 index 203439e..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcCharacter.kt +++ /dev/null @@ -1,147 +0,0 @@ -package com.github.cfogrady.vbnfc.data - -import java.util.Objects - -open class NfcCharacter( - val dimId: UShort, - var charIndex: UShort, - var stage: Byte, - var attribute: Attribute, - var ageInDays: Byte, - var nextAdventureMissionStage: Byte, // next adventure mission stage on the character's dim - var mood: Byte, - var vitalPoints: UShort, - var transformationCountdown: UShort, - var injuryStatus: InjuryStatus, - var trophies: UShort, - var currentPhaseBattlesWon: UShort, - var currentPhaseBattlesLost: UShort, - var totalBattlesWon: UShort, - var totalBattlesLost: UShort, - var activityLevel: Byte, - var heartRateCurrent: UByte, - var transformationHistory: Array -) { - - data class Transformation( - val toCharIndex: Byte, - val yearsSince1988: Byte, - val month: Byte, - val day: Byte) - - enum class AbilityRarity { - None, - Common, - Rare, - SuperRare, - SuperSuperRare, - UltraRare, - } - - enum class Attribute { - None, - Virus, - Data, - Vaccine, - Free - } - enum class InjuryStatus { - None, - Injury, - InjuryHealed, - InjuryTwo, - InjuryTwoHealed, - InjuryThree, - InjuryThreeHealed, - InjuryFour, - } - - fun getTransformationHistoryString(separator: String = System.lineSeparator()): String { - val builder = StringBuilder() - for(i in transformationHistory.indices) { - builder.append(transformationHistory[i]) - if(i != transformationHistory.size-1) { - builder.append(separator) - } - } - return builder.toString() - } - - - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as NfcCharacter - - if (dimId != other.dimId) return false - if (charIndex != other.charIndex) return false - if (stage != other.stage) return false - if (attribute != other.attribute) return false - if (ageInDays != other.ageInDays) return false - if (nextAdventureMissionStage != other.nextAdventureMissionStage) return false - if (mood != other.mood) return false - if (vitalPoints != other.vitalPoints) return false - if (transformationCountdown != other.transformationCountdown) return false - if (injuryStatus != other.injuryStatus) return false - if (trophies != other.trophies) return false - if (currentPhaseBattlesWon != other.currentPhaseBattlesWon) return false - if (currentPhaseBattlesLost != other.currentPhaseBattlesLost) return false - if (totalBattlesWon != other.totalBattlesWon) return false - if (totalBattlesLost != other.totalBattlesLost) return false - if (activityLevel != other.activityLevel) return false - if (heartRateCurrent != other.heartRateCurrent) return false - if (!transformationHistory.contentEquals(other.transformationHistory)) return false - - return true - } - - override fun hashCode(): Int { - return Objects.hash( - dimId, - charIndex, - stage, - attribute, - ageInDays, - nextAdventureMissionStage, - mood, - vitalPoints, - transformationCountdown, - injuryStatus, - trophies, - currentPhaseBattlesWon, - currentPhaseBattlesLost, - totalBattlesWon, - totalBattlesLost, - activityLevel, - heartRateCurrent, - transformationHistory.contentHashCode() - ) - } - - override fun toString(): String { - return """NfcCharacter( - dimId=$dimId, - charIndex=$charIndex, - stage=$stage, - attribute=$attribute, - ageInDays=$ageInDays, - nextAdventureMissionStage=$nextAdventureMissionStage, - mood=$mood, - vitalPoints=$vitalPoints, - transformationCountdown=$transformationCountdown, - injuryStatus=$injuryStatus, - trophies=$trophies, - currentPhaseBattlesWon=$currentPhaseBattlesWon, - currentPhaseBattlesLost=$currentPhaseBattlesLost, - totalBattlesWon=$totalBattlesWon, - totalBattlesLost=$totalBattlesLost, - activityLevel=$activityLevel, - heartRateCurrent=$heartRateCurrent, - transformationHistory=${transformationHistory.contentToString()} -)""" - } - - -} diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcData.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcData.kt deleted file mode 100644 index cf31d7b..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcData.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.github.cfogrady.vbnfc.data - -class NfcData(val nfcCharacter: NfcCharacter, val nfcDevice: NfcDevice) diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcDevice.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcDevice.kt deleted file mode 100644 index 026bd90..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcDevice.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.cfogrady.vbnfc.data - -import java.util.BitSet - -open class NfcDevice(private val registeredDims: BitSet) { - fun isDimRegistered(dimId: UShort): Boolean { - return registeredDims[dimId.toInt()] - } -} \ No newline at end of file diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcHeader.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcHeader.kt deleted file mode 100644 index 8e3b34b..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/data/NfcHeader.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.github.cfogrady.vbnfc.data - -import com.github.cfogrady.vbnfc.NfcDataTranslator -import com.github.cfogrady.vbnfc.getUInt16 -import com.github.cfogrady.vbnfc.toByteArray -import java.nio.ByteOrder - -open class NfcHeader ( - val deviceId: UShort, - val deviceSubType: UShort, - val vbCompatibleTagIdentifier: ByteArray, // this is a magic number used to verify that the tag is a VB. - val status: Byte, - val operation: Byte, - var dimIdBytes: ByteArray, - val appFlag: Byte, - val nonce: ByteArray, -) { - - fun getDimId(): UShort { - return dimIdBytes.getUInt16(0, ByteOrder.BIG_ENDIAN) - } - - fun setDimId(dimId: UShort) { - dimIdBytes = dimId.toByteArray(ByteOrder.BIG_ENDIAN) - } -} \ No newline at end of file diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/vb/VBNfcDataTranslator.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/vb/VBNfcDataTranslator.kt deleted file mode 100644 index 36ae719..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/vb/VBNfcDataTranslator.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.github.cfogrady.vbnfc.vb - -import com.github.cfogrady.vbnfc.CryptographicTransformer -import com.github.cfogrady.vbnfc.NfcDataTranslator -import com.github.cfogrady.vbnfc.TagCommunicator -import com.github.cfogrady.vbnfc.data.DeviceSubType -import com.github.cfogrady.vbnfc.data.DeviceType -import com.github.cfogrady.vbnfc.data.NfcCharacter -import com.github.cfogrady.vbnfc.data.NfcHeader -import com.github.cfogrady.vbnfc.getUInt16 - -class VBNfcDataTranslator(override val cryptographicTransformer: CryptographicTransformer) : NfcDataTranslator { - - companion object { - const val OPERATION_PAGE: Byte = 0x6 - } - - override fun finalizeByteArrayFormat(bytes: ByteArray) { - TODO("Not yet implemented") - } - - override fun getOperationCommandBytes(header: NfcHeader, operation: Byte): ByteArray { - val vbHeader = header as VBNfcHeader - return byteArrayOf(TagCommunicator.NFC_WRITE_COMMAND, OPERATION_PAGE, header.status, header.dimIdBytes[1], operation, vbHeader.reserved) - } - - override fun parseNfcCharacter(bytes: ByteArray): NfcCharacter { - TODO("Not yet implemented") - } - - override fun parseHeader(headerBytes: ByteArray): NfcHeader { - val header = VBNfcHeader( - deviceType = DeviceType.VitalSeriesDeviceType, - deviceSubType = headerBytes.getUInt16(6), - vbCompatibleTagIdentifier = headerBytes.sliceArray(0..3), // this is a magic number used to verify that the tag is a VB. - status = headerBytes[8], - dimId = headerBytes[9], - operation = headerBytes[10], - reserved = headerBytes[11], - appFlag = headerBytes[12], - nonce = headerBytes.sliceArray(13..15) - ) - return header - } -} \ No newline at end of file diff --git a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/vb/VBNfcHeader.kt b/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/vb/VBNfcHeader.kt deleted file mode 100644 index 8ca8c8b..0000000 --- a/vb-nfc-reader/src/main/java/com/github/cfogrady/vbnfc/vb/VBNfcHeader.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.github.cfogrady.vbnfc.vb - -import com.github.cfogrady.vbnfc.data.DeviceType -import com.github.cfogrady.vbnfc.data.NfcHeader - -class VBNfcHeader( - deviceType: UShort, - deviceSubType: UShort, - vbCompatibleTagIdentifier: ByteArray, - status: Byte, - operation: Byte, - dimId: Byte, - val reserved: Byte, - appFlag: Byte, - nonce: ByteArray - ) : NfcHeader( - deviceId = deviceType, - deviceSubType = deviceSubType, - vbCompatibleTagIdentifier = vbCompatibleTagIdentifier, - status = status, - operation = operation, - dimIdBytes = byteArrayOf(0, dimId), - appFlag = appFlag, - nonce = nonce, -) \ No newline at end of file diff --git a/vb-nfc-reader/src/main/res/values/arrays.xml b/vb-nfc-reader/src/main/res/values/arrays.xml deleted file mode 100644 index f46a6fe..0000000 --- a/vb-nfc-reader/src/main/res/values/arrays.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/vb-nfc-reader/src/main/res/values/strings.xml b/vb-nfc-reader/src/main/res/values/strings.xml deleted file mode 100644 index 33a89dd..0000000 --- a/vb-nfc-reader/src/main/res/values/strings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/CryptographicTransformerHelper.kt b/vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/CryptographicTransformerHelper.kt deleted file mode 100644 index cc8c881..0000000 --- a/vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/CryptographicTransformerHelper.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.github.cfogrady.vbnfc - -import java.nio.charset.StandardCharsets -import java.util.Base64 -import javax.crypto.Cipher -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.SecretKeySpec -import kotlin.random.Random - -// This class allows for creating new test keys -class CryptographicTransformerHelper { - - companion object { - fun generateAesKey(): String { - val combinedKey = ByteArray(24) - for (i in combinedKey.indices) { - combinedKey[i] = Random.nextInt(48, 58 + 26).toByte() - if(combinedKey[i] > 57) { - combinedKey[i] = (combinedKey[i] + 7).toByte() - } - } - return combinedKey.toString(StandardCharsets.UTF_8) - } - - fun generateHMacKey(aesKey: String, hmacKey: String = generateRandomPlainTextHmacKey()): String { - val hmacKeyData = hmacKey.toByteArray(StandardCharsets.UTF_8) - val encryptedHmacKey = encryptAesCbcPkcs5Padding(aesKey, hmacKeyData) - return Base64.getEncoder().encodeToString(encryptedHmacKey) - } - - private fun generateRandomPlainTextHmacKey(): String { - val key = ByteArray(4) - for (i in key.indices) { - key[i] = Random.nextInt(33, 126).toByte() - } - return key.toString(StandardCharsets.UTF_8) - } - - private fun encryptAesCbcPkcs5Padding(key: String, data: ByteArray): ByteArray { - val keyBytes = key.toByteArray(StandardCharsets.UTF_8) - val rightSizedKey = keyBytes.copyOf(32) - val ivBytes = keyBytes.copyOfRange(key.length - 16, key.length) - val secretKeySpec = SecretKeySpec(rightSizedKey, "AES") - val ivParameterSpec = IvParameterSpec(ivBytes) - val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") - cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec) - return cipher.doFinal(data) - } - } -} \ No newline at end of file diff --git a/vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/CryptographicTransformerTest.kt b/vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/CryptographicTransformerTest.kt deleted file mode 100644 index 712c44e..0000000 --- a/vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/CryptographicTransformerTest.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.github.cfogrady.vbnfc - -import io.mockk.every -import io.mockk.mockkStatic -import org.junit.Assert -import org.junit.Test - -class CryptographicTransformerTest { - - val testTagId = byteArrayOf(0x04, 0x40, 0xaf.toByte(), 0xa2.toByte(), 0xee.toByte(), 0x0f, 0x90.toByte()) - - val testAesKey = "8A4PEGIXJS454EFRTX9F5PCT" - val testHmacKey1 = "40nz2LdPI99D+x748XmQmw==" - val testHmacKey2 = "5Jz9lWtNg28qxqIBoR5kLw==" - val testSubstitutionCipher = intArrayOf(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) - - @OptIn(ExperimentalStdlibApi::class) - @Test - fun createPasswordCreatesExpectedPassword() { - - mockkStatic(android.util.Log::class) - every { android.util.Log.i(any(), any()) } answers { - val message = it.invocation.args[1] as String - println(message) - 1 - } - - val cryptographicTransformer = CryptographicTransformer(testHmacKey1, testHmacKey2, testAesKey, testSubstitutionCipher) - - val result = cryptographicTransformer.createNfcPassword(testTagId) - val expected = "a3c83dd7" - - Assert.assertEquals(expected, result.toHexString()) - } - - @OptIn(ExperimentalStdlibApi::class) - @Test - fun dataEncryptionAndDecryptionWorks() { - val cryptographicTransformer = CryptographicTransformer(testHmacKey1, testHmacKey2, testAesKey, testSubstitutionCipher) - - val characters = listOf( - "000000000000000000000000000000000000000000000000000000000000000010400010040010001000000000001094104000100400100010000000000010940000000000000000000400840203008d0000000000000000000400840203008d00000006000300060003000001010014000000060003000600030000010100140156025309850000000000000000d6100156025309850000000000000000d610000000000000280000000000000000280000000000000000030c08302402279424022624022524022424022324020151002402290124022904240229000000f2ffffffffffffffffffffffff000000f4ffffffffffffffff00000000000000f80000000000000000000014860000009a0000000000000000000014860000009a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101010101010101000000000000008702020202020202020000000001010033000000000000000000000000000000000000000000000000000000000000000014c5400000000000000000000000001914c540000000000000000000000000190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "000000000000000000000000000000000000000000000000000000000000000010400010040010001000000000001094104000100400100010000000000010940000000000000000000500820302008c0000000000000000000500820302008c000b00030002000b000b000001010028000b00030002000b000b0000010100280464028b04b4000000000000000308b80464028b04b4000000000000000308b80474000000001500000000000000008d0002000000000000000000002401062d240105240104240103240102240101c80024010601240106042401060000008605240116ffffffffffffffff00000038ffffffffffffffff00000000000000f80005000f000a00000000046b0000008d0005000f000a00000000046b0000008d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030303030303030300000000000000210404040404040404000000000101003a000000000000000000000000000000000000000000000000000000000000000014c5400000000000000000000000001914c540000000000000000000000000190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - ) - val expectedEncryptions = listOf( - "74b46e2d78292ce251a84e644f5451dd4aa2c6d782a9aeef2c3229103c7a26e5d9c2c53d2f63077a1cf9ae18efc382edca9e50d7d861e2927cd9df2494a0772ff1b8791bae7883a862d218559277db6a9665f18da0f1caa92ccc903dbc80e66367ee39b2f243cc0b5bfcc2131dfeb9d361179d4033517c4ebbceea15ab9bfb27a9a05cb45e5dfe37287a010db3bcfd9a6f1cc54a31ea7da193dbd341e83997ad80713d5fd19c7d76a6dbedfb25049ab5472e4094d0949f19c853b2ac6c6827412904fd1683fae61ea1a64508e9243e04bdfdee63ff98321204fd4fd2a17112c0bd5aa7c11986ea7bc00110dedea2d0644ea5ea3f6e928f8c6c98107eeedbfd1b774d07df237dc294f3b8fccaa8ab2e1c59de2c695f367214f55accc2e43ca0b2c021161d3c8b9ea2405717d6884d089d848d82b37a9ed711a8e9809336d05bab0091face97671e9260d4ae741e94ef1f8d950ff390dd05bfa28adb6b72a8214192be530af26db6abda69dce0707d3d92f44beb1f01f24d7c1123ad25d37349bf7d5777723f1acb56d2f96ba435ffa505c3ae3d270c85bcb64aabac0d15d8128f7fe34cc303a74f8d42871a25d452a1ef033b824b17e51b808b5363f2f1da5a57c3fcc881b57028e76155f6d49e35e43bd142747c3a4a14217fa8600a6e0d3cdbc6b5598510023ad0897d38ca04e78a78e198ee76e784d6337ad8fa65e4b617ea11433fb3d9d7d3269a7b5e1ff9a4cd723f3fc4f81768816619fadf21b5276f31d704bba1a3a9afb0363cca3ddb272bdced2d252e21824d2828b7c36cdd37202cd5a6b5224e505f87188d3c63af33c8916aa8ae0116dd1028c370236591a4413559fe40d14dcdf72959a122def9b4c6cf5d928142a66b0dcf0ffa5d447b53a8661e3578a49d632e0285d180814116a3e78fc00fc01106a248af8afa329a69054b827e41a62abdc65074554fa2f07b773d56bae73252efa374f47397c1d36e056eb9d32b6dcf18f40669a5b23723c475c50c5ba4154b550c67dd90d4a6919686c69fdcfd7d4d988a0df5e420b6240068ae8aa07c88c38bac3b6ce7a87c8df0f540cc3c5be2180b70127c523102ed9be2cfb25a032089d47d05db6dbde2758239ad54b94756906922ed7e7c4ecf6b256c658417fa8003100c72de1dee627c1a0c670dbc91596e4dc0d4393eb24884b41979e8ff3d5b0583416750d1d856a2a689cd", - "74b46e2d78292ce251a84e644f5451dd4aa2c6d782a9aeef2c3229103c7a26e5d9c2c53d2f63077a1cf9ae18efc382edca9e50d7d861e2927cd9df2494a0772ff1b8791bae7883a862d318539376db6b9665f18da0f1caa92ccd903bbd81e66267e539b7f242cc065bf4c2131dfeb9ef611c9d4533507c43bbc6ea15ab9bfb1bac925c6c536cfe37287a010db3bf23326a2ec5923cdb7da193dbd341e83a490584053d5fd19c4076a6dbedfb25049a10472c4094d0949f19cb5fba9c6c6b06f82907de1680dbe61d86a64629e9273e9dbdfded4cff98313d04fd4cfda17112b4478159281986ea7bc00110dedea2d0a84ea5ea3f6e928f8c6c98107eeedbfd1b774807d02377c294f3b8ec27a8ab2e0b59db2c665f3c7214f55adc2fe43ca0a5c021161d3c8b9ea2405717d6884d089d848d82b37a9ed711a8e9809336d05bab0091face97671e9260d4ae741e94ef1f8d950ff390dd05bfa28adb6b72a8214190bc5108f06fb4a9da69dce0707d3d34f24ded1907f44b7a1123ad25d37349b67d5777723f1acb56d2f96ba435ffa505c3ae3d270c85bcb64aabac0d15d8128f7fe34cc303a74f8d42871a25d452a1ef033b824b17e51b808b5363f2f1da5a57c3fcc881b57028e76155f6d49e35e43bd142747c3a4a14217fa8600a6e0d3cdbc6b5598510023ad0897d38ca04e78a78e198ee76e784d6337ad8fa65e4b617ea11433fb3d9d7d3269a7b5e1ff9a4cd723f3fc4f81768816619fadf21b5276f31d704bba1a3a9afb0363cca3ddb272bdced2d252e21824d2828b7c36cdd37202cd5a6b5224e505f87188d3c63af33c8916aa8ae0116dd1028c370236591a4413559fe40d14dcdf72959a122def9b4c6cf5d928142a66b0dcf0ffa5d447b53a8661e3578a49d632e0285d180814116a3e78fc00fc01106a248af8afa329a69054b827e41a62abdc65074554fa2f07b773d56bae73252efa374f47397c1d36e056eb9d32b6dcf18f40669a5b23723c475c50c5ba4154b550c67dd90d4a6919686c69fdcfd7d4d988a0df5e420b6240068ae8aa07c88c38bac3b6ce7a87c8df0f540cc3c5be2180b70127c523102ed9be2cfb25a032089d47d05db6dbde2758239ad54b94756906922ed7e7c4ecf6b256c658417fa8003100c72de1dee627c1a0c670dbc91596e4dc0d4393eb24884b41979e8ff3d5b0583416750d1d856a2a689cd", - ) - for (i in characters.indices) { - val encrypted = cryptographicTransformer.encryptData(characters[i].hexToByteArray(), testTagId) - Assert.assertEquals(expectedEncryptions[i], encrypted.toHexString()) - val decrypted = cryptographicTransformer.decryptData(encrypted, testTagId) - Assert.assertEquals(characters[i], decrypted.toHexString()) - } - } -} \ No newline at end of file diff --git a/vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/be/BENfcDataTranslatorTest.kt b/vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/be/BENfcDataTranslatorTest.kt deleted file mode 100644 index 816117e..0000000 --- a/vb-nfc-reader/src/test/java/com/github/cfogrady/vbnfc/be/BENfcDataTranslatorTest.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.github.cfogrady.vbnfc.be - -import com.github.cfogrady.vbnfc.ChecksumCalculator -import com.github.cfogrady.vbnfc.CryptographicTransformer -import com.github.cfogrady.vbnfc.data.NfcCharacter -import io.mockk.mockkClass -import org.junit.Assert -import org.junit.Test - -class BENfcDataTranslatorTest { - @OptIn(ExperimentalStdlibApi::class) - @Test - fun testNfcCharacterParsing() { - val nfcBytes = "000000000000000000000000000000000000000000000000000000000000000010400010040010001000000000001094104000100400100010000000000010940000000000000000000500820302008c0000000000000000000500820302008c000b00030002000b000b000001010028000b00030002000b000b0000010100280464028b04b4000000000000000308b80464028b04b4000000000000000308b80474000000001500000000000000008d0002000000000000000000002401062d240105240104240103240102240101c80024010601240106042401060000008605240116ffffffffffffffff00000038ffffffffffffffff00000000000000f80005000f000a00000000046b0000008d0005000f000a00000000046b0000008d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010101010101010100000000000000210202020202020202000000000101003a000000000000000000000000000000000000000000000000000000000000000014c5400000000000000000000000001914c540000000000000000000000000190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".hexToByteArray() - val mockCryptographicTransformer = mockkClass(CryptographicTransformer::class) - val checksumCalculator = ChecksumCalculator() - val beNfcDataTranslator = BENfcDataTranslator(mockCryptographicTransformer, checksumCalculator) - - val character = beNfcDataTranslator.parseNfcCharacter(nfcBytes) - val expectedCharacter = BENfcCharacter( - dimId = 130u, - charIndex = 5u, - stage = 3, - attribute = NfcCharacter.Attribute.Data, - ageInDays = 0, - mood = 100, - characterCreationFirmwareVersion = FirmwareVersion(1, 1), - nextAdventureMissionStage = 4, - vitalPoints = 1204u, - transformationCountdownInMinutes = 776u, - injuryStatus = NfcCharacter.InjuryStatus.None, - trainingPp = 11u, - currentPhaseBattlesWon = 3u, - currentPhaseBattlesLost = 2u, - totalBattlesWon = 11u, - totalBattlesLost = 11u, - activityLevel = 2, - heartRateCurrent = 139u, - transformationHistory = arrayOf(NfcCharacter.Transformation(0, 36, 1, 6), - NfcCharacter.Transformation(1, 36, 1, 6), - NfcCharacter.Transformation(4, 36, 1, 6), - NfcCharacter.Transformation(5, 36, 1, 22), - NfcCharacter.Transformation(-1, -1, -1, -1), - NfcCharacter.Transformation(-1, -1, -1, -1), - NfcCharacter.Transformation(-1, -1, -1, -1), - NfcCharacter.Transformation(-1, -1, -1, -1), - ), - trainingHp = 5u, - trainingAp = 15u, - trainingBp = 10u, - remainingTrainingTimeInMinutes = 1131u, - itemEffectMentalStateValue = 0, - itemEffectMentalStateMinutesRemaining = 0, - itemEffectActivityLevelValue = 0, - itemEffectActivityLevelMinutesRemaining = 0, - itemEffectVitalPointsChangeValue = 0, - itemEffectVitalPointsChangeMinutesRemaining = 0, - abilityRarity = NfcCharacter.AbilityRarity.None, - abilityType = 0u, - abilityBranch = 0u, - abilityReset = 0, - rank = 0, - itemType = 0, - itemMultiplier = 0, - itemRemainingTime = 0, - appReserved1 = byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - appReserved2 = arrayOf(0u, 0u, 0u), - otp0 = "0101010101010101".hexToByteArray(), - otp1 = "0202020202020202".hexToByteArray() - ) - Assert.assertEquals(expectedCharacter, character) - } -} \ No newline at end of file