android: lifetime query + cali consistency check + real-device checklist
This commit is contained in:
@@ -110,6 +110,11 @@ class IrSession(context: Context) {
|
||||
var lastInfo1: ByteArray? = null
|
||||
private set
|
||||
|
||||
/** Device power-on lifetime in ms (official getDevLifeTime); -1 = unknown. */
|
||||
@Volatile
|
||||
var deviceLifetimeMs: Long = -1
|
||||
private set
|
||||
|
||||
fun identitySnapshot(): CameraIdentity = identity.copy()
|
||||
|
||||
/** Connect + start the live stream. Must be called after USB permission. */
|
||||
@@ -207,6 +212,24 @@ class IrSession(context: Context) {
|
||||
}
|
||||
DebugLog.log("session", "cali info: size=$caliSize date=$caliDate")
|
||||
|
||||
// 3b) GetLifeTime (official getDevLifeTime): 675 -> 0x5BB5B561 {magic, ms}.
|
||||
// Non-blocking: the official app just logs when this fails.
|
||||
writeCmd(conn, epOut, MagProtocol.cmd4(MagProtocol.CMD_GET_LIFETIME), "GetLifeTime")
|
||||
readResp(conn, epResp, "GetLifeTime")?.let { r ->
|
||||
if (r.second == MagProtocol.RSP_SEND_LIFETIME) {
|
||||
// protocol doc: payload {magic, i32 ms}; official Java reads the
|
||||
// bare {i32 ms} right after the response magic — accept both.
|
||||
val ms = when {
|
||||
r.third.size >= 8 && MagProtocol.u32(r.third, 0) == MagProtocol.RSP_SEND_LIFETIME ->
|
||||
MagProtocol.u32(r.third, 4)
|
||||
r.third.size >= 4 -> MagProtocol.u32(r.third, 0)
|
||||
else -> null
|
||||
}
|
||||
if (ms != null) deviceLifetimeMs = ms.toLong() and 0xFFFFFFFFL
|
||||
}
|
||||
}
|
||||
DebugLog.log("session", "device lifetime=${deviceLifetimeMs}ms")
|
||||
|
||||
// 4) calibration file: cache hit or fetch from EP 0x84
|
||||
val ddt = obtainCali(conn, ep84, epOut, epResp, caliSize, caliDate, bundledDdt)
|
||||
DebugLog.log("session", "ddt bytes ${ddt.size}")
|
||||
@@ -294,7 +317,14 @@ class IrSession(context: Context) {
|
||||
if (cache.isFile && cache.length() == size) {
|
||||
DebugLog.log("session", "cali cache hit: ${cache.name}")
|
||||
return try {
|
||||
cache.readBytes()
|
||||
val cached = cache.readBytes()
|
||||
// consistency check only: the cache stays authoritative
|
||||
DebugLog.log(
|
||||
"session",
|
||||
"cali cache vs bundled DDT: " +
|
||||
if (md5(cached).contentEquals(md5(bundled))) "identical" else "differ",
|
||||
)
|
||||
cached
|
||||
} catch (e: Exception) {
|
||||
DebugLog.log("session", "cali cache read failed -> bundled: $e")
|
||||
bundled
|
||||
@@ -349,6 +379,10 @@ class IrSession(context: Context) {
|
||||
return out
|
||||
}
|
||||
|
||||
/** MD5 digest of a byte array (cali consistency check only). */
|
||||
private fun md5(bytes: ByteArray): ByteArray =
|
||||
java.security.MessageDigest.getInstance("MD5").digest(bytes)
|
||||
|
||||
private fun notify(state: State, message: String?) {
|
||||
DebugLog.log("session", "state -> $state msg=$message")
|
||||
listener?.onStateChanged(state, message)
|
||||
@@ -516,7 +550,8 @@ class IrSession(context: Context) {
|
||||
"stream",
|
||||
"stats: reads=$readCount frames=$frameCount rendered=$renderCount " +
|
||||
"timeouts=$timeouts fps=%.1f ".format(Locale.US, fps) +
|
||||
"renderState=${pipe.frameIndex()} ref=${pipe.hasReference()}",
|
||||
"renderState=${pipe.frameIndex()} ref=${pipe.hasReference()}" +
|
||||
" lifetime=${deviceLifetimeMs}",
|
||||
)
|
||||
lastLog = now
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ object MagProtocol {
|
||||
const val RSP_SEND_CALI_FILE = 0x5BB5B55D
|
||||
const val RSP_SEND_CALI_INFO = 0x5BB5B55E
|
||||
|
||||
/** D2P_SendLifeTime (1538635105) — reply to GetLifeTime: {u32 magic, i32 ms}. */
|
||||
const val RSP_SEND_LIFETIME = 0x5BB5B561
|
||||
|
||||
/**
|
||||
* 4-byte LITTLE-ENDIAN command — byte-identical to the official app's
|
||||
* GlobalFunc.intToByteArray (a&255 first). CRITICAL: ByteBuffer.putInt
|
||||
|
||||
Reference in New Issue
Block a user