Pārlūkot izejas kodu

feat(CAN总线): 新增CAN总线硬件数据处理
- 新增ByteArray和String扩展方法,用于小端字节序十六进制字符串转换
- `CanCommand`:
- 新增`setLatchBits_1to5`方法,用于批量写入5位控制(低5位有效),适配5路/柜体同构
- `CanHardwareHelper`:
- 实现多项硬件控制和数据读取功能,包括:
- 控制钥匙锁、锁扣、充电
- 控制所有钥匙锁扣打开
- 检查底座状态
- 中断垃圾桶状态读取
- 控制所有钥匙充电关闭
- 根据MAC地址获取钥匙信息
- 更新钥匙就绪状态和电量
- 读取钥匙和锁的RFID字符串
- 获取便携式底座和锁底座数据
- 控制便携式底座锁扣
- 控制钥匙锁扣和充电(组合操作)

周文健 2 mēneši atpakaļ
vecāks
revīzija
e3f45eaf9f

+ 8 - 0
data/src/main/java/com/grkj/data/hardware/can/CanCommand.kt

@@ -162,6 +162,14 @@ object CanCommands {
             return SdoRequest.Write(nodeId, Command.CONTROL_REG, 0x00, shortLE(v, 0b1_1111), 2)
         }
 
+        /**
+         * 批量写入 5 位控制(低5位有效),适配 5路/柜体同构
+         */
+        fun setLatchBits_1to5(target: Int, locked: Boolean): SdoRequest.Write {
+            val v = if (locked) 0b1_1111 else 0b0_0000
+            return SdoRequest.Write(nodeId, Command.CONTROL_REG, 0x00, shortLE(v, target), 2)
+        }
+
         /** 单位控制(1..5) */
         fun controlOne_1to5(slotIndex1to5: Int, locked: Boolean): SdoRequest.Write {
             require(slotIndex1to5 in 1..5) { "slotIndex must be 1..5" }

+ 132 - 12
data/src/main/java/com/grkj/data/hardware/can/CanHardwareHelper.kt

@@ -4,12 +4,19 @@ import com.grkj.data.hardware.DockData
 import com.grkj.data.hardware.IHardwareHelper
 import com.grkj.data.hardware.modbus.DeviceConst
 import com.grkj.data.model.res.CabinetSlotsRecord
+import com.grkj.shared.utils.extension.toHexFromLe
+import com.grkj.shared.utils.face.arcsoft.CameraHelper
 import com.grkj.shared.utils.i18n.I18nManager
+import com.sik.comm.impl_can.toCommMessage
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import kotlin.math.log
 
 /**
  * Can硬件读写帮助类
  */
 class CanHardwareHelper : IHardwareHelper {
+    private val logger: Logger = LoggerFactory.getLogger(CanHardwareHelper::class.java)
     override fun getKeyMacByRfid(rfid: String): String? {
         return CanHelper.getKeyByRfid(rfid)?.mac
     }
@@ -63,7 +70,14 @@ class CanHardwareHelper : IHardwareHelper {
         mac: String,
         done: ((ByteArray) -> Unit)?
     ) {
-        TODO("Not yet implemented")
+        val keyDevice = CanHelper.getKeyDeviceByMac(mac)
+        keyDevice?.let {
+            val req = CanCommands.forDevice(keyDevice.nodeId)
+                .controlLatch(keyDevice.id, if (isOpen) 0 else 1)
+            CanHelper.writeTo(req) {
+                done?.invoke(it.toCommMessage().payload)
+            }
+        }
     }
 
     override fun controlLockBuckle(
@@ -72,7 +86,15 @@ class CanHardwareHelper : IHardwareHelper {
         lockIdxList: MutableList<Int>,
         done: ((ByteArray) -> Unit)?
     ) {
-        TODO("Not yet implemented")
+        slaveAddress?.let {
+            val target = lockIdxList.fold(1) { acc, i ->
+                acc or (1 shl i)
+            }
+            val req = CanCommands.forDevice(slaveAddress).setLatchBits_1to5(target, !isOpen)
+            CanHelper.writeTo(req) {
+                done?.invoke(it.toCommMessage().payload)
+            }
+        }
     }
 
     override fun controlKeyCharge(
@@ -81,11 +103,44 @@ class CanHardwareHelper : IHardwareHelper {
         slaveAddress: Int?,
         done: ((ByteArray) -> Unit)?
     ) {
-        TODO("Not yet implemented")
+        slaveAddress?.let {
+            val leftOn = if (idx == 0 && isOpen) true else if (idx == 0) false else null
+            val rightOn = if (idx == 1 && isOpen) true else if (idx == 1) false else null
+            val req = CanCommands.forDevice(slaveAddress)
+                .setCharge(leftOn, rightOn)
+            CanHelper.writeTo(req) {
+                done?.invoke(it.toCommMessage().payload)
+            }
+        }
+    }
+
+    override fun controlKeyCharge(
+        isOpen: Boolean,
+        mac: String,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        val keyDevice = CanHelper.getKeyDeviceByMac(mac)
+        keyDevice?.let {
+            val leftOn = if (it.id == 0 && isOpen) true else if (it.id == 0) false else null
+            val rightOn = if (it.id == 1 && isOpen) true else if (it.id == 1) false else null
+            val req = CanCommands.forDevice(it.nodeId)
+                .setCharge(leftOn, rightOn)
+            CanHelper.writeTo(req) {
+                done?.invoke(it.toCommMessage().payload)
+            }
+        }
     }
 
     override fun controlAllKeyBuckleOpen(complete: () -> Unit) {
-        TODO("Not yet implemented")
+        val keys = CanHelper.getDeviceByDeviceType(CanDeviceConst.DEVICE_KEY_DOCK)
+        keys.forEach {
+            val req = CanCommands.forDevice(it.key).setLatch(false, false)
+            CanHelper.writeTo(req)
+        }
+    }
+
+    override fun checkDock(): Boolean {
+        return true
     }
 
     override fun interruptReadTrashBinStatus(interrupt: Boolean) {
@@ -93,15 +148,43 @@ class CanHardwareHelper : IHardwareHelper {
     }
 
     override fun controlAllKeyChargeDown() {
-        TODO("Not yet implemented")
+        val keys = CanHelper.getDeviceByDeviceType(CanDeviceConst.DEVICE_KEY_DOCK)
+        keys.forEach {
+            val req = CanCommands.forDevice(it.key).setCharge(false, false)
+            CanHelper.writeTo(req)
+        }
     }
 
     override fun getKeyBeanByMac(mac: String): DockData.KeyDock.KeyBean? {
-        TODO("Not yet implemented")
+        val deviceKey = CanHelper.getKeyDeviceByMac(mac)
+        return deviceKey?.let {
+            DockData.KeyDock.KeyBean().apply {
+                this.addr = it.nodeId
+                this.idx = it.id
+                this.row = it.nodeId
+                this.rfid = it.rfid
+                this.mac = it.mac
+                this.isExist = it.isExist
+                this.type = it.deviceType
+                this.isReady = it.isReady
+                this.newHardware = it.newHardware
+            }
+        }
+    }
+
+    override fun updateKeyReadyStatus(
+        mac: String,
+        isReady: Boolean,
+        from: Int
+    ) {
+        logger.info("updateKeyReadyStatus mac:$mac isReady:$isReady from:$from")
+        val deviceKey = CanHelper.getKeyDeviceByMac(mac)
+        deviceKey?.isReady = isReady
     }
 
     override fun updateKeyPower(power: Int, mac: String) {
-        TODO("Not yet implemented")
+        val deviceKey = CanHelper.getKeyDeviceByMac(mac)
+        deviceKey?.power = power
     }
 
     override fun controlLockBuckle(
@@ -110,7 +193,13 @@ class CanHardwareHelper : IHardwareHelper {
         lockIdxList: Int,
         done: ((ByteArray) -> Unit)?
     ) {
-        TODO("Not yet implemented")
+        slaveAddress?.let {
+            val target = lockIdxList
+            val req = CanCommands.forDevice(slaveAddress).setLatchBits_1to5(target, !isOpen)
+            CanHelper.writeTo(req) {
+                done?.invoke(it.toCommMessage().payload)
+            }
+        }
     }
 
     override fun readKeyRfidStr(
@@ -118,7 +207,21 @@ class CanHardwareHelper : IHardwareHelper {
         idx: Int,
         done: ((Int, String) -> Unit)?
     ) {
-        TODO("Not yet implemented")
+        slaveAddress?.let {
+            val req = CanCommands.forDevice(slaveAddress).let {
+                if (idx == 0) {
+                    it.getLeftRfid()
+                } else {
+                    it.getRightRfid()
+                }
+            }
+            CanHelper.readFrom(req) {
+                it?.let {
+                    logger.info("返回的数据:${it.toCommMessage().payload}")
+                    done?.invoke(idx, it.toCommMessage().payload.toHexFromLe())
+                }
+            }
+        }
     }
 
     override fun readLockRfidStr(
@@ -126,7 +229,17 @@ class CanHardwareHelper : IHardwareHelper {
         lockIdx: Int,
         done: ((String) -> Unit)?
     ) {
-        TODO("Not yet implemented")
+        slaveAddress?.let {
+            val req = CanCommands.forDevice(slaveAddress).let {
+                it.getSlotRfid_1to5(lockIdx)
+            }
+            CanHelper.readFrom(req) {
+                it?.let {
+                    logger.info("返回的数据:${it.toCommMessage().payload}")
+                    done?.invoke(it.toCommMessage().payload.toHexFromLe())
+                }
+            }
+        }
     }
 
     override fun getPortableDock(): List<DockData.PortableDock> {
@@ -139,7 +252,12 @@ class CanHardwareHelper : IHardwareHelper {
         slaveAddress: Int?,
         done: ((ByteArray) -> Unit)?
     ) {
-        TODO("Not yet implemented")
+        slaveAddress?.let {
+            val req = CanCommands.forDevice(slaveAddress).controlLatch(idx, if (isOpen) 0 else 1)
+            CanHelper.writeTo(req) {
+                done?.invoke(it.toCommMessage().payload)
+            }
+        }
     }
 
     override fun getLockDockData(): List<DockData.LockDock> {
@@ -168,7 +286,9 @@ class CanHardwareHelper : IHardwareHelper {
         slaveAddress: Int?,
         done: ((ByteArray) -> Unit)?
     ) {
-        TODO("Not yet implemented")
+        controlKeyBuckle(!isOpen, idx, slaveAddress) {
+            controlKeyCharge(isOpen, idx, slaveAddress, done)
+        }
     }
 
     override fun getLockSlotPosition(lockNfc: String): String {

+ 39 - 1
shared/src/main/java/com/grkj/shared/utils/extension/ByteArray.kt

@@ -106,4 +106,42 @@ fun ByteArray.crc16(from: Int = 0, to: Int = size) : ByteArray {
     val c1 = (0xff00 and value shr 8).toByte()
     val c2 = (0xff and value).toByte()
     return byteArrayOf(c1, c2)
-}
+}
+
+/**
+ * ByteArray扩展:小端字节序 → 十六进制字符串(大端显示)
+ */
+fun ByteArray.toHexFromLe(
+    prefix: Boolean = false,
+    upper: Boolean = true,
+    width: Int? = null
+): String {
+    val table = if (upper) "0123456789ABCDEF" else "0123456789abcdef"
+    val sb = StringBuilder(this.size * 2)
+    for (i in this.lastIndex downTo 0) {
+        val v = this[i].toInt() and 0xFF
+        sb.append(table[v ushr 4])
+        sb.append(table[v and 0x0F])
+    }
+    var s = sb.toString()
+    if (width != null) s = s.padStart(width, '0')
+    return if (prefix) "0x$s" else s
+}
+
+/**
+ * String扩展:十六进制字符串(含空格、0x等) → 十六进制字符串(小端转大端)
+ */
+fun String.toHexFromLe(
+    prefix: Boolean = false,
+    upper: Boolean = true,
+    width: Int? = null
+): String {
+    val clean = this.replace(Regex("0x", RegexOption.IGNORE_CASE), "")
+        .replace(Regex("[^0-9A-Fa-f]"), "")
+    require(clean.length % 2 == 0) { "hex长度必须为偶数" }
+    val bytes = ByteArray(clean.length / 2) { i ->
+        clean.substring(i * 2, i * 2 + 2).toInt(16).toByte()
+    }
+    return bytes.toHexFromLe(prefix, upper, width)
+}
+