|
|
@@ -32,11 +32,59 @@ class Hlk223Client(
|
|
|
): Pair<Int, ByteArray> {
|
|
|
val req: CommMessage = Hlk223.msg(mid, data, timeoutMs)
|
|
|
logger.info("请求:${req.payload.toHexStrings()}")
|
|
|
+
|
|
|
+ val rsp: CommMessage = protocol.send(deviceId, req)
|
|
|
+ logger.info("返回:${rsp.payload.toHexStrings()}")
|
|
|
+
|
|
|
+ // 🔽 关键:自动拆帧(单帧 / 多帧 / 含 NOTE 都能兜)
|
|
|
+ val parsed: List<Pair<Int, ByteArray>> =
|
|
|
+ try {
|
|
|
+ Hlk223.autoParse(rsp.payload) // 你前面那版我已经给了;没有就搬运进去
|
|
|
+ } catch (t: Throwable) {
|
|
|
+ // 兜底:老固件返回干净单帧时,保持兼容
|
|
|
+ logger.warn("autoParse 失败,尝试单帧解析: ${t.message}")
|
|
|
+ listOf(Hlk223.parseOne(rsp.payload))
|
|
|
+ }
|
|
|
+
|
|
|
+ if (parsed.isEmpty()) error("No valid frame found in response")
|
|
|
+
|
|
|
+ if (parsed.size > 1) {
|
|
|
+ // 把多出来的帧打日志,帮你定位设备“爱发 NOTE/IMAGE”的毛病
|
|
|
+ val mids = parsed.joinToString(",") { "0x${it.first.toString(16)}" }
|
|
|
+ logger.info("多帧返回,MIDs=[$mids]")
|
|
|
+ }
|
|
|
+
|
|
|
+ return pickBestFrame(parsed)
|
|
|
+ }
|
|
|
+
|
|
|
+ @Suppress("unused")
|
|
|
+ private suspend fun exchangeAll(
|
|
|
+ mid: Int,
|
|
|
+ data: ByteArray = byteArrayOf(),
|
|
|
+ timeoutMs: Int? = 3000
|
|
|
+ ): List<Pair<Int, ByteArray>> {
|
|
|
+ val req: CommMessage = Hlk223.msg(mid, data, timeoutMs)
|
|
|
+ logger.info("请求:${req.payload.toHexStrings()}")
|
|
|
val rsp: CommMessage = protocol.send(deviceId, req)
|
|
|
logger.info("返回:${rsp.payload.toHexStrings()}")
|
|
|
- return Hlk223.parseOne(rsp.payload)
|
|
|
+
|
|
|
+ return try {
|
|
|
+ Hlk223.autoParse(rsp.payload).also {
|
|
|
+ if (it.isEmpty()) error("No valid frames")
|
|
|
+ }
|
|
|
+ } catch (t: Throwable) {
|
|
|
+ listOf(Hlk223.parseOne(rsp.payload))
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ private fun pickBestFrame(frames: List<Pair<Int, ByteArray>>): Pair<Int, ByteArray> {
|
|
|
+ // 优先选 REPLY
|
|
|
+ frames.firstOrNull { it.first == Hlk223.MID.REPLY }?.let { return it }
|
|
|
+ // 没有 REPLY:如果只有一帧就用那一帧,否则退回第一帧
|
|
|
+ return frames.singleOrNull() ?: frames.first()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
private fun u8(b: Byte) = b.toInt() and 0xFF
|
|
|
private fun s16(hi: Int, lo: Int): Int = ((hi shl 8) or lo).toShort().toInt()
|
|
|
|
|
|
@@ -161,7 +209,8 @@ class Hlk223Client(
|
|
|
val deadline = System.currentTimeMillis() + (timeoutSec + 2) * 1000L
|
|
|
while (System.currentTimeMillis() < deadline &&
|
|
|
!verifyStop.get() &&
|
|
|
- currentCoroutineContext().isActive) {
|
|
|
+ currentCoroutineContext().isActive
|
|
|
+ ) {
|
|
|
val ack: CommMessage = try {
|
|
|
io.readRaw(
|
|
|
timeoutMs = singleReadTimeoutMs,
|
|
|
@@ -193,6 +242,7 @@ class Hlk223Client(
|
|
|
val nid = data.getOrNull(0)?.let { u8(it) } ?: continue
|
|
|
when (nid) {
|
|
|
NID_FACE_STATE -> if (data.size >= 1 + 16) {
|
|
|
+ logger.info("人脸数据:${data.toHexStrings()}")
|
|
|
fun s(i: Int) = s16(u8(data[i + 1]), u8(data[i]))
|
|
|
val st = s(1)
|
|
|
val left = s(3);
|
|
|
@@ -208,6 +258,7 @@ class Hlk223Client(
|
|
|
right,
|
|
|
bottom
|
|
|
) else null
|
|
|
+ logger.info("人脸位置:${left},${top},${right},${bottom}")
|
|
|
onFaceState(rect, st, yaw, pitch, roll)
|
|
|
}
|
|
|
|