bcbc7b440c
사용자앱 (feature/tab-navigation) 과 패키지 이름 일치. namespace + applicationId 둘 다 com.medithings.vesiscan 로 변경 (기존 데모 앱은 재설치 필요). ## 변경 범위 - Kotlin 148 파일: package + import 문 (714 occurrences) - 디렉토리 이동: com/example/medilightv2android → com/medithings/vesiscan (main, test, androidTest 각각) - app/build.gradle.kts: namespace, applicationId - docs/FLAVOR_DEMO_STABLE.md: 참조 갱신 - V41DetectorCH4Test: BvDispatchResult.methodChosen → method (dto field name fix) ## 주의 - applicationId 가 바뀌므로 기존 데모 앱 (com.example.medilightv2android.demo) 은 Android 관점에서 다른 앱으로 취급 — 재설치 시 PIN/설정 초기화됨. - Fresh install 권장. 기존 앱 (com.example...) 은 별도로 uninstall 필요. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
72 lines
2.6 KiB
Kotlin
72 lines
2.6 KiB
Kotlin
package com.medithings.vesiscan.ble
|
|
|
|
object CRC16 {
|
|
private const val POLYNOMIAL: Int = 0x1021
|
|
private const val INITIAL_VALUE: Int = 0xFFFF
|
|
|
|
fun calculate(data: ByteArray): Int {
|
|
var crc = INITIAL_VALUE
|
|
for (byte in data) {
|
|
crc = crc xor ((byte.toInt() and 0xFF) shl 8)
|
|
for (j in 0 until 8) {
|
|
crc = if ((crc and 0x8000) != 0) {
|
|
(crc shl 1) xor POLYNOMIAL
|
|
} else {
|
|
crc shl 1
|
|
}
|
|
crc = crc and 0xFFFF
|
|
}
|
|
}
|
|
return crc
|
|
}
|
|
|
|
fun calculate(string: String): Int = calculate(string.toByteArray(Charsets.UTF_8))
|
|
|
|
fun appendCRC(data: ByteArray): ByteArray {
|
|
val crc = calculate(data)
|
|
return data + byteArrayOf(
|
|
(crc and 0xFF).toByte(), // Low byte first (Little Endian)
|
|
((crc shr 8) and 0xFF).toByte() // High byte
|
|
)
|
|
}
|
|
|
|
fun appendCRC(string: String): ByteArray = appendCRC(string.toByteArray(Charsets.UTF_8))
|
|
|
|
fun verify(data: ByteArray): Boolean {
|
|
if (data.size < 2) return false
|
|
val payload = data.copyOfRange(0, data.size - 2)
|
|
val receivedCRC = (data[data.size - 2].toInt() and 0xFF) or
|
|
((data[data.size - 1].toInt() and 0xFF) shl 8)
|
|
return calculate(payload) == receivedCRC
|
|
}
|
|
|
|
fun buildCommand(cmd: String, params: IntArray = intArrayOf()): ByteArray {
|
|
val cmdBytes = "$cmd?".toByteArray(Charsets.UTF_8)
|
|
val paramBytes = ByteArray(params.size * 2)
|
|
for (i in params.indices) {
|
|
paramBytes[i * 2] = (params[i] and 0xFF).toByte() // Low byte
|
|
paramBytes[i * 2 + 1] = ((params[i] shr 8) and 0xFF).toByte() // High byte
|
|
}
|
|
return appendCRC(cmdBytes + paramBytes)
|
|
}
|
|
|
|
fun buildCommandASCII(cmd: String, asciiParams: String = ""): ByteArray {
|
|
return appendCRC("$cmd?$asciiParams".toByteArray(Charsets.UTF_8))
|
|
}
|
|
|
|
/** 파라미터를 16비트 Big Endian으로 추가 (펌웨어 테스터와 동일 포맷) */
|
|
fun buildCommandBE(cmd: String, params: IntArray = intArrayOf()): ByteArray {
|
|
val cmdBytes = "$cmd?".toByteArray(Charsets.UTF_8)
|
|
val paramBytes = ByteArray(params.size * 2)
|
|
for (i in params.indices) {
|
|
paramBytes[i * 2] = ((params[i] shr 8) and 0xFF).toByte() // High byte first
|
|
paramBytes[i * 2 + 1] = (params[i] and 0xFF).toByte() // Low byte
|
|
}
|
|
return appendCRC(cmdBytes + paramBytes)
|
|
}
|
|
|
|
fun buildSimpleCommand(cmd: String): ByteArray {
|
|
return appendCRC(cmd.toByteArray(Charsets.UTF_8))
|
|
}
|
|
}
|