浏览代码

refactor(优化):
- modbus结构新增,模块拆除
- 硬件状态的界面修改

周文健 6 月之前
父节点
当前提交
62a0d2df0a

+ 0 - 2
app/src/main/java/com/grkj/iscs/BusinessManager.kt

@@ -217,8 +217,6 @@ object BusinessManager {
     /****************************************** ModBus ******************************************/
 
     fun connectDock(isNeedInit: Boolean = false) {
-        // 不再使用SlaveCount,改用地址池
-//        ModBusController.setSlaveCount(100)
         ModBusController.interruptReadTrashBinStatus(false)
         ModBusController.start(MyApplication.instance!!.applicationContext)
         ModBusController.unregisterListener(MyApplication.instance!!.applicationContext)

+ 4 - 4
app/src/main/java/com/grkj/iscs/modbus/DockBean.kt

@@ -263,7 +263,7 @@ class DockBean(
                     }
 
                     val changeList = mutableListOf<DeviceBean>()
-                    for (i in 0 until getLockList().size) {
+                    for (i in 0 until 8) {
                         getLockList()[i].lockEnabled = tempList[i]
                     }
 
@@ -286,7 +286,7 @@ class DockBean(
 
                     val changeList = mutableListOf<DeviceBean>()
                     // 锁具变化
-                    for (i in 0 until getLockList().size) {
+                    for (i in 0 until 3) {
                         getLockList()[i].lockEnabled = tempList[i]
                     }
                     // 蓝牙钥匙变化
@@ -322,8 +322,8 @@ class DockBean(
                         return null
                     }
                     val changeList = mutableListOf<DeviceBean>()
-                    for (i in getLockList().size - 2 until getLockList().size) {
-                        getLockList()[i].lockEnabled = tempList[i]
+                    for (i in 0..1) {
+                        getLockList()[getLockList().size - 2 + i].lockEnabled = tempList[i]
                     }
 
                     LogUtil.i("锁具刷新状态 : $changeList")

+ 64 - 0
app/src/main/java/com/grkj/iscs/modbus/FrameTask.kt

@@ -0,0 +1,64 @@
+package com.grkj.iscs.modbus
+
+import com.grkj.iscs.extentions.crc16
+
+class FrameTask(
+    val req: ByteArray,
+    val done: ((res: ByteArray) -> Unit)?    // 响应回调
+) {
+
+    /**
+     * 是否允许重发
+     */
+    var allowRetransmission: Boolean = true
+
+    /**
+     * 上次发送时间
+     */
+    var lastSent: Long = 0
+
+    /**
+     * 已发送次数
+     */
+    var sentCount = 0
+
+    /**
+     * 最小发送间隔
+     */
+    var minSendInterval: Int = MODBUS_MIN_SEND_INTERVAL
+
+
+    fun waitIfNecessary() {
+        val interval = System.nanoTime() - lastSent
+        if (interval < minSendInterval) {
+            Thread.sleep((minSendInterval - interval) / 1000_000)
+        }
+    }
+
+    fun shouldSend(): Boolean {
+        return if (allowRetransmission) {
+            sentCount < 3
+        } else {
+            sentCount < 1
+        }
+    }
+
+    fun afterSent() {
+        sentCount++
+        lastSent = System.nanoTime()
+    }
+
+    /**
+     * 判断 res 是否是 frame 的响应
+     */
+    fun match(res: ByteArray): Boolean {
+        // 从机地址 和 功能码 必须相同
+        if (res.size < 5 || req[0] != res[0] || req[1] != res[1]) {
+            return false
+        }
+        // 报文2 的 CRC校验得正确
+        val crc16 = res.crc16(0, res.size - 2)
+        return crc16[0] == res[res.size - 2] && crc16[1] == res[res.size - 1]
+    }
+
+}

+ 87 - 0
app/src/main/java/com/grkj/iscs/modbus/MBFrame.kt

@@ -0,0 +1,87 @@
+package com.grkj.iscs.modbus
+
+import com.grkj.iscs.extentions.crc16
+
+/**
+ * ModBus 数据帧
+ */
+class MBFrame(
+
+    // 类型
+    val type: Byte,
+    // 数据域:D1 和 D2
+    val data: ByteArray
+
+) {
+
+    /**
+     * @param index 从机序号
+     */
+    fun compile(index: Int): ByteArray {
+        val bytes = ByteArray(4 + data.size)
+        // TODO 从机开始地址0x01
+//        bytes[0] = (0x80 + index).toByte()
+        bytes[0] = (1 + index).toByte()
+        bytes[1] = type
+        for (i in data.indices) {
+            bytes[2 + i] = data[i]
+        }
+        val crc16 = bytes.crc16(0, bytes.size - 2)
+        bytes[bytes.size - 2] = crc16[0]
+        bytes[bytes.size - 1] = crc16[1]
+        return bytes
+
+//        val cmd = byteArrayOf((1 + index).toByte()) + byteArrayOf(type) + data
+//        return cmd + cmd.crc16()
+    }
+
+    /**
+     * @param address 从机地址
+     */
+    fun compile(address: Byte): ByteArray {
+        val bytes = ByteArray(4 + data.size)
+        bytes[0] = address
+        bytes[1] = type
+        for (i in data.indices) {
+            bytes[2 + i] = data[i]
+        }
+        val crc16 = bytes.crc16(0, bytes.size - 2)
+        bytes[bytes.size - 2] = crc16[0]
+        bytes[bytes.size - 1] = crc16[1]
+        return bytes
+    }
+
+    companion object {
+        /**
+         * 读取设备类型
+         */
+        val READ_DEVICE_TYPE = MBFrame(
+            FRAME_TYPE_READ,
+            byteArrayOf(0x00, 0x00, 0x00, 0x01)
+        )
+
+        /**
+         * 读钥匙/锁具/便携式底座状态
+         */
+        val READ_STATUS = MBFrame(
+            FRAME_TYPE_READ,
+            byteArrayOf(0x00, 0x10, 0x00, 0x01)
+        )
+
+        /**
+         * 读卡扣状态(钥匙、锁的0-7、便携式的锁和钥匙)
+         */
+        val READ_BUCKLE_STATUS = MBFrame(
+            FRAME_TYPE_READ,
+            byteArrayOf(0x00, 0x11, 0x00, 0x01)
+        )
+
+        /**
+         * 读卡扣状态(锁的9、10)
+         */
+        val READ_LOCK_BUCKLE_EXTRA_STATUS = MBFrame(
+            FRAME_TYPE_READ,
+            byteArrayOf(0x00, 0x12, 0x00, 0x01)
+        )
+    }
+}

+ 104 - 0
app/src/main/java/com/grkj/iscs/modbus/ModBusCMDHelper.kt

@@ -0,0 +1,104 @@
+package com.grkj.iscs.modbus
+
+/**
+ * 通信指令帮助工具
+ */
+object ModBusCMDHelper {
+    /**
+     * 生成锁具/便携式底座 单个锁具卡扣开关指令
+     */
+    fun generateLockBuckleCmd(isOpen: Boolean, lockIndex: Int): MBFrame {
+        var str = ""
+        val idx = lockIndex - (lockIndex / 8) * 8
+        for (i in 7 downTo 0) {
+            str += if (i == idx) {
+                "1"
+            } else {
+                "0"
+            }
+        }
+
+        // 第三位是 是否响应,第四位是操作哪个,操作默认全是0或者1,使用第三位响应来进行操作
+        return MBFrame(
+            FRAME_TYPE_WRITE,
+            byteArrayOf(0x00,
+                if (lockIndex in 0..7) 0x11 else 0x12,
+                str.toInt(2).toByte(),
+                if (isOpen) 0x00 else 0xFF.toByte()
+            )
+        )
+    }
+
+    /**
+     * 生成多个锁具卡扣开关指令(只能针对同一个底座,不能跨底座)
+     */
+    fun generateLockBuckleCmd(isOpen: Boolean, lockIndexList: MutableList<Int>): MutableList<MBFrame> {
+        var str = ""
+        val rstList = mutableListOf<MBFrame>()
+        val smallIdxList = lockIndexList.filter { it in 0..7 }
+        val bigIdxList = lockIndexList.filter { it in 8..15 }
+        if (smallIdxList.isNotEmpty()) {
+            for (i in 7 downTo 0) {
+                str += if (smallIdxList.contains(i)) {
+                    "1"
+                } else {
+                    "0"
+                }
+            }
+            rstList.add(MBFrame(FRAME_TYPE_WRITE, byteArrayOf(0x00, 0x11, str.toInt(2).toByte(), if (isOpen) 0x00 else 0xFF.toByte())))
+        }
+        if (bigIdxList.isNotEmpty()) {
+            str = ""
+            for (i in 7 downTo 0) {
+                str += if (bigIdxList.contains(i + 8)) {
+                    "1"
+                } else {
+                    "0"
+                }
+            }
+            rstList.add(MBFrame(FRAME_TYPE_WRITE, byteArrayOf(0x00, 0x12, str.toInt(2).toByte(), if (isOpen) 0x00 else 0xFF.toByte())))
+        }
+        return rstList
+    }
+
+
+
+    /**
+     * 生成钥匙底座灯光指令
+     *
+     * @param leftAction、rightAction 0:保持当前状态 1:点亮 2:熄灭 默认0
+     */
+    @Deprecated("已取消")
+    fun generateKeyLightCmd(leftAction: Int = 0, rightAction: Int = 0): MBFrame {
+        return MBFrame(
+            FRAME_TYPE_WRITE,
+            // TODO 第三个是高位,第四个是低位
+            byteArrayOf(0x00, 0x15, rightAction.toByte(), leftAction.toByte())
+        )
+    }
+
+    /**
+     * 操作钥匙/便携式底座钥匙卡扣,一次只操作一个卡扣
+     *
+     * @param isOpen true:开操作 false:关操作
+     * @param index 0:左 1:右 便携式底座钥匙传0
+     */
+    fun generateKeyBuckleCmd(isOpen: Boolean, index: Int): MBFrame {
+        return MBFrame(
+            FRAME_TYPE_WRITE,
+            byteArrayOf(0x00, 0x11, if (index == 1) 0b00010000.toByte() else 0b0000001, if (isOpen) 0x00 else 0xFF.toByte())
+        )
+    }
+
+    /**
+     * 生成RFID 读指令
+     *
+     * @param idx 锁具底座锁具:0-9  钥匙底座钥匙:0(left)-1(right)  便携式底座锁具:0-2  便携式底座钥匙:4   便携式底座卡:8
+     */
+    fun generateRfidCmd(idx: Int): MBFrame {
+        return MBFrame(
+            FRAME_TYPE_READ,
+            byteArrayOf(0x00, (0x20 + idx * 4).toByte(), 0x00, 0x04)
+        )
+    }
+}

+ 13 - 0
app/src/main/java/com/grkj/iscs/modbus/ModBusConstants.kt

@@ -0,0 +1,13 @@
+package com.grkj.iscs.modbus
+
+/**
+ * modbus 最小发送间隔(150豪秒)
+ */
+// TODO 超时的可能也是用的这个,看情况是否增加到500
+const val MODBUS_MIN_SEND_INTERVAL = 500_000_000
+
+const val FRAME_TYPE_READ: Byte = 0x03
+const val FRAME_TYPE_WRITE: Byte = 0x06
+const val FRAME_TYPE_SCANNER: Byte = 0x43
+const val FRAME_TYPE_WRITE_MULTI: Byte = 0x10
+const val FRAME_TYPE_WRITE_FILE: Byte = 0x15

+ 61 - 81
app/src/main/java/com/grkj/iscs/modbus/ModBusController.kt

@@ -23,7 +23,9 @@ import java.util.stream.Collectors
  * ModBus 主控板控制器
  */
 object ModBusController {
-
+    /**
+     * 是否初始化完成
+     */
     var isInitReady = false
 
     /**
@@ -31,37 +33,45 @@ object ModBusController {
      */
     var dockList: MutableList<DockBean> = mutableListOf()
 
+    /**
+     * 监听状态类型
+     */
     private const val LISTENER_TYPE_STATUS = 3
 
     // 主控板管理器
     var modBusManager: ModBusManager? = null
-    private var slaveCount: Int = 0
 
+    /**
+     * 监听器
+     */
     private val listeners = ArrayList<StatusListener>()
 
     // 是否中断读取状态
     private var interruptReadStatus: ArrayList<Boolean> = ArrayList()
 
+    /**
+     * 重复时间
+     */
     // TODO 临时改成5s
     const val REPEAT_FREQUENCY = 800L
 
-    class StatusListener(
-        val key: Any,
-        val listener: (MBFrame, Any) -> Unit,
-        val type: Int
-    )
-
+    /**
+     * 中断读取
+     */
     fun interruptReadTrashBinStatus(interrupt: Boolean) {
         interruptReadStatus.clear()
         interruptReadStatus.add(interrupt)
     }
 
+    /**
+     * 启动通信引擎
+     */
     @ExperimentalUnsignedTypes
     fun start(ctx: Context) {
         modBusManager?.stop()
         PortManager.openCtrlBord(ctx)
             ?.let { pm ->
-                return@let ModBusManager(slaveCount, pm, true)
+                return@let ModBusManager(pm, true)
             }
             // 间隔 1 秒读一遍桶的状态
             ?.repeatSendToAll(MBFrame.READ_STATUS, {
@@ -106,10 +116,16 @@ object ModBusController {
             ?.start()
     }
 
+    /**
+     * 注册监听器
+     */
     fun registerStatusListener(key: Any, listener: (MBFrame, Any) -> Unit) {
         listeners.add(StatusListener(key, listener, LISTENER_TYPE_STATUS))
     }
 
+    /**
+     * 取消注册监听器
+     */
     fun unregisterListener(key: Any) {
         val it = listeners.iterator()
         while (it.hasNext()) {
@@ -119,10 +135,16 @@ object ModBusController {
         }
     }
 
+    /**
+     * 停止引擎
+     */
     fun stop() {
         modBusManager?.stop()
     }
 
+    /**
+     * 引擎是否运行中
+     */
     fun isRunning(): Boolean? {
         return modBusManager?.isRunning()
     }
@@ -266,7 +288,7 @@ object ModBusController {
         if (byteArray.isEmpty()) {
             return null
         }
-        val dockB = dockList.find { it.addr == byteArray[0] && it.type == DOCK_TYPE_KEY }
+        val dockB = dockList.find { it.addr == byteArray[0] && it.type == DOCK_TYPE_LOCK }
         return dockB?.parseExtraLockStatus(byteArray)
     }
 
@@ -316,7 +338,7 @@ object ModBusController {
     }
 
     /**
-     * 开/关锁具卡扣
+     * 开/关锁具卡扣
      */
     fun controlLockBuckle(
         isOpen: Boolean,
@@ -325,7 +347,7 @@ object ModBusController {
         done: ((res: ByteArray) -> Unit)? = null
     ) {
         slaveAddress?.let {
-            modBusManager?.generateLockBuckleCmd(isOpen, lockIdx)?.let { cmd ->
+            ModBusCMDHelper.generateLockBuckleCmd(isOpen, lockIdx)?.let { cmd ->
                 modBusManager?.sendTo(it, cmd) { res ->
                     done?.invoke(res)
                 }
@@ -333,6 +355,9 @@ object ModBusController {
         }
     }
 
+    /**
+     * 开/关锁具卡扣 多
+     */
     fun controlLockBuckle(
         isOpen: Boolean,
         slaveAddress: Byte?,
@@ -340,7 +365,7 @@ object ModBusController {
         done: ((res: ByteArray) -> Unit)? = null
     ) {
         slaveAddress?.let {
-            modBusManager?.generateLockBuckleCmd(isOpen, lockIdxList)?.let { cmdList ->
+            ModBusCMDHelper.generateLockBuckleCmd(isOpen, lockIdxList)?.let { cmdList ->
                 cmdList.forEach { cmd ->
                     modBusManager?.sendTo(it, cmd) { res ->
                         done?.invoke(res)
@@ -359,7 +384,7 @@ object ModBusController {
         done: ((isLeft: Boolean, res: ByteArray) -> Unit)? = null
     ) {
         slaveAddress?.let {
-            modBusManager?.generateRfidCmd(idx)?.let { cmd ->
+            ModBusCMDHelper.generateRfidCmd(idx)?.let { cmd ->
                 modBusManager?.sendTo(it, cmd) {
                     done?.invoke(idx == 0, it)
                 }
@@ -372,7 +397,7 @@ object ModBusController {
      */
     fun readLockRfid(slaveAddress: Byte?, lockIdx: Int, done: ((res: ByteArray) -> Unit)? = null) {
         slaveAddress?.let {
-            modBusManager?.generateRfidCmd(lockIdx)?.let { cmd ->
+            ModBusCMDHelper.generateRfidCmd(lockIdx)?.let { cmd ->
                 modBusManager?.sendTo(it, cmd) { res ->
                     done?.invoke(res)
                 }
@@ -385,7 +410,7 @@ object ModBusController {
      */
     fun readPortalCaseCardRfid(slaveAddress: Byte?, done: ((res: ByteArray) -> Unit)? = null) {
         slaveAddress?.let {
-            modBusManager?.generateRfidCmd(8)?.let { cmd ->
+            ModBusCMDHelper.generateRfidCmd(8)?.let { cmd ->
                 modBusManager?.sendTo(it, cmd) { res ->
                     done?.invoke(res)
                 }
@@ -417,14 +442,6 @@ object ModBusController {
             mac
     }
 
-    /**
-     * 通过RFID更新对应的Mac
-     */
-    fun updateKeyMacByRfid(rfid: String, mac: String) {
-        dockList.find { it.type == DOCK_TYPE_KEY }?.getKeyList()?.find { it.rfid == rfid }?.mac =
-            mac
-    }
-
     /**
      * 更新锁具RFID
      */
@@ -441,49 +458,6 @@ object ModBusController {
             ?.find { it.idx == lockIdx }?.lockEnabled = lockEnabled
     }
 
-    /**
-     * 设备是否存在,加入deviceType防止有重复的但是不同类型的
-     *
-     * @param deviceType {@link [com.grkj.iscs.model.bo.DeviceTakeUpdateBO]<class>#[deviceType]}
-     */
-    fun isDeviceExist(rfid: String, deviceType: Int): Boolean {
-        return when (deviceType) {
-            DEVICE_TYPE_KEY -> {
-                dockList.find { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }
-                    ?.getKeyList()?.find { it.rfid == rfid } != null
-            }
-
-            DEVICE_TYPE_LOCK -> {
-                dockList.find { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }
-                    ?.getLockList()?.find { it.rfid == rfid } != null
-            }
-
-            else -> {
-                false
-            }
-        }
-    }
-
-    /**
-     * 操作钥匙灯
-     *
-     * @param leftAction、rightAction 0:保持当前状态 1:点亮 2:熄灭 默认0
-     */
-    fun controlKeyLight(
-        slaveAddress: Byte?,
-        leftAction: Int = 0,
-        rightAction: Int = 0,
-        done: ((res: ByteArray) -> Unit)? = null
-    ) {
-        slaveAddress?.let {
-            modBusManager?.generateKeyLightCmd(leftAction, rightAction)?.let { cmd ->
-                modBusManager?.sendTo(it, cmd) {
-                    done?.invoke(it)
-                }
-            }
-        }
-    }
-
     /**
      * 控制钥匙卡扣
      */
@@ -508,7 +482,7 @@ object ModBusController {
         done: ((res: ByteArray) -> Unit)? = null
     ) {
         slaveAddress?.let {
-            modBusManager?.generateKeyBuckleCmd(isOpen, if (isLeft) 0 else 1)?.let { cmd ->
+            ModBusCMDHelper.generateKeyBuckleCmd(isOpen, if (isLeft) 0 else 1)?.let { cmd ->
                 modBusManager?.sendTo(it, cmd) { res ->
                     done?.invoke(res)
                 }
@@ -532,19 +506,17 @@ object ModBusController {
             .flatMap { it.getKeyList() }.find { it.mac == mac }
     }
 
+    /**
+     * 根据底座获取钥匙
+     */
     fun getKeyByDock(dockAddr: Byte?, isLeft: Boolean): DockBean.KeyBean? {
         dockAddr ?: return null
         return dockList.find { it.addr == dockAddr }?.getKeyList()?.find { it.isLeft == isLeft }
     }
 
     /**
-     * 根据RFID找锁具
+     * 钥匙是否存在
      */
-    fun getLockByRfid(rfid: String): DockBean.LockBean? {
-        return dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }
-            .flatMap { it.getLockList() }.find { it.rfid == rfid }
-    }
-
     fun isKeyExist(dockAddr: Byte?, isLeft: Boolean): Boolean {
         dockAddr ?: return false
         return dockList.find { it.addr == dockAddr }?.getKeyList()
@@ -569,6 +541,9 @@ object ModBusController {
             ?.find { it.idx == lockIdx }?.lockEnabled == true
     }
 
+    /**
+     * 获取挂锁是否存在
+     */
     fun isLockExist(dockAddr: Byte?, lockIdx: Int): Boolean {
         dockAddr ?: return false
         return dockList.find { it.addr == dockAddr }?.getLockList()
@@ -645,13 +620,6 @@ object ModBusController {
         }
     }
 
-    fun getDockByLockNfc(nfc: String): DockBean? {
-        return dockList.find {
-            (it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE)
-                    && it.getLockList().any { it.rfid == nfc }
-        }
-    }
-
     /**
      * 根据类型获取底座列表
      */
@@ -659,12 +627,18 @@ object ModBusController {
         return dockList.filter { it.type == type }
     }
 
+    /**
+     * 根据底座类型获取钥匙列表
+     */
     fun getKeyByDockType(type: Byte): MutableList<DockBean.KeyBean>? {
         return dockList.find { it.type == type }?.let {
             it.getKeyList()
         }
     }
 
+    /**
+     * 全部锁扣的开关
+     */
     fun controlAllLockBuckles(isOpen: Boolean) {
         dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }
             .forEach { dockBean ->
@@ -676,6 +650,9 @@ object ModBusController {
             }
     }
 
+    /**
+     * 打印全部底座信息
+     */
     fun printDockInfo() {
         LogUtil.i("当前底座列表 : $dockList")
         dockList.forEach { dockBean ->
@@ -704,6 +681,9 @@ object ModBusController {
         }
     }
 
+    /**
+     * 更新设备类型
+     */
     fun updateDeviceType() {
         LogUtil.i("____________________________________")
         readDeviceType { res ->

+ 9 - 299
app/src/main/java/com/grkj/iscs/modbus/ModBusManager.kt

@@ -12,35 +12,10 @@ import com.grkj.iscs.util.log.LogUtil
 import com.grkj.iscs.view.fragment.DockTestFragment
 import java.util.concurrent.LinkedBlockingQueue
 
-/**
- * modbus 最小发送间隔(150豪秒)
- */
-// TODO 超时的可能也是用的这个,看情况是否增加到500
-//const val MODBUS_MIN_SEND_INTERVAL = 150_000_000
-const val MODBUS_MIN_SEND_INTERVAL = 500_000_000
-
-/**
- * 最大从机数量
- */
-const val MODBUS_MAX_SLAVE_COUNT = 16
-
-/**
- * 从机状态:未变化
- */
-const val MODBUS_SLAVE_STATUS__NO_CHANGE = -1
-
-/**
- * 从机状态:已经满溢
- */
-const val MODBUS_SLAVE_STATUS__FULL = 0b00100000
-
-
 /**
  * ModBus 协议管理器
  */
 class ModBusManager(
-    // 从机数量
-    var slaveCount: Int,
     // 串口管理器
     val portManager: PortManager,
     // 是否输出详细信息
@@ -122,7 +97,6 @@ class ModBusManager(
                             LogUtil.i("发送:${req.toHexStrings()}")
                         }
                     } else {
-//                        Tip.toast("无法与主控板通讯")
                         LogUtil.w("无法与主控板通讯")
                     }
                 } else {
@@ -130,27 +104,11 @@ class ModBusManager(
                     // 放弃处理,回调空数据
                     done?.let { it(byteArrayOf()) }
                     sending = null
-//                    onFrameTimeout()
                 }
             }
         }
     }
 
-    private var timeouts = 0
-    private var lastTimeout = 0L
-
-    private fun onFrameTimeout() {
-        val now = jvmSeconds()
-        if (now - lastTimeout > 10) {
-            timeouts = 0
-        }
-        // 如果连续超时达到 15 次,则重建 Modbus 连接
-        if (++timeouts > 15) {
-//            EventBus.getDefault().post(ConfigEvent())
-        }
-        lastTimeout = now
-    }
-
     /**
      * 循环发送给所有从机
      * @param frame 发送报文
@@ -207,7 +165,6 @@ class ModBusManager(
     ) {
         sendTo(mSlaveAddressList[index], frame) { res ->
             resList.add(res)
-//            if (index >= slaveCount - 1) {
             if (index >= mSlaveAddressList.size - 1) {
                 // 已经发送完
                 if (running) {
@@ -233,26 +190,23 @@ class ModBusManager(
         minSendIntervalNanoSeconds: Int = MODBUS_MIN_SEND_INTERVAL,
         done: ((res: ByteArray) -> Unit)? = null
     ) {
-//        if (slaveCount <= 0) {
         if (mSlaveAddressList.size <= 0) {
             LogUtil.i("sendTo($slaveAddress), 地址池大小为0, 返回空数据")
             done?.invoke(byteArrayOf())
             return
         }
-//        if (index < 0 || index >= slaveCount) {
-//            throw IllegalArgumentException("index [${index}] out of bound [${slaveCount}]")
-//        }
         if (mSlaveAddressList.none { it == slaveAddress }) {
             throw IllegalArgumentException("slaveAddress [${slaveAddress}] is not configed")
         }
-
-//        val task = FrameTask(frame.compile(index), done)
         val task = FrameTask(frame.compile(slaveAddress), done)
         task.allowRetransmission = allowRetransmission
         task.minSendInterval = minSendIntervalNanoSeconds
         pendings.add(task)
     }
 
+    /**
+     * 开始通信
+     */
     fun start() {
         thread = Thread {
             while (running) {
@@ -266,263 +220,19 @@ class ModBusManager(
         thread?.start()
     }
 
+    /**
+     * 是否运行
+     */
     fun isRunning(): Boolean {
         return running
     }
 
+    /**
+     * 停止运行
+     */
     fun stop() {
         running = false
         thread?.interrupt()
         portManager.close()
     }
-
-    /**
-     * 生成锁具/便携式底座 单个锁具卡扣开关指令
-     */
-    fun generateLockBuckleCmd(isOpen: Boolean, lockIndex: Int): MBFrame {
-        var str = ""
-        val idx = lockIndex - (lockIndex / 8) * 8
-        for (i in 7 downTo 0) {
-            str += if (i == idx) {
-                "1"
-            } else {
-                "0"
-            }
-        }
-
-        // 第三位是 是否响应,第四位是操作哪个,操作默认全是0或者1,使用第三位响应来进行操作
-        return MBFrame(
-            FRAME_TYPE_WRITE,
-            byteArrayOf(0x00,
-                if (lockIndex in 0..7) 0x11 else 0x12,
-                str.toInt(2).toByte(),
-                if (isOpen) 0x00 else 0xFF.toByte()
-            )
-        )
-    }
-
-    /**
-     * 生成多个锁具卡扣开关指令(只能针对同一个底座,不能跨底座)
-     */
-    fun generateLockBuckleCmd(isOpen: Boolean, lockIndexList: MutableList<Int>): MutableList<MBFrame> {
-        var str = ""
-        val rstList = mutableListOf<MBFrame>()
-        val smallIdxList = lockIndexList.filter { it in 0..7 }
-        val bigIdxList = lockIndexList.filter { it in 8..15 }
-        if (smallIdxList.isNotEmpty()) {
-            for (i in 7 downTo 0) {
-                str += if (smallIdxList.contains(i)) {
-                    "1"
-                } else {
-                    "0"
-                }
-            }
-            rstList.add(MBFrame(FRAME_TYPE_WRITE, byteArrayOf(0x00, 0x11, str.toInt(2).toByte(), if (isOpen) 0x00 else 0xFF.toByte())))
-        }
-        if (bigIdxList.isNotEmpty()) {
-            str = ""
-            for (i in 7 downTo 0) {
-                str += if (bigIdxList.contains(i + 8)) {
-                    "1"
-                } else {
-                    "0"
-                }
-            }
-            rstList.add(MBFrame(FRAME_TYPE_WRITE, byteArrayOf(0x00, 0x12, str.toInt(2).toByte(), if (isOpen) 0x00 else 0xFF.toByte())))
-        }
-        return rstList
-    }
-
-
-
-    /**
-     * 生成钥匙底座灯光指令
-     *
-     * @param leftAction、rightAction 0:保持当前状态 1:点亮 2:熄灭 默认0
-     */
-    @Deprecated("已取消")
-    fun generateKeyLightCmd(leftAction: Int = 0, rightAction: Int = 0): MBFrame {
-        return MBFrame(
-            FRAME_TYPE_WRITE,
-            // TODO 第三个是高位,第四个是低位
-            byteArrayOf(0x00, 0x15, rightAction.toByte(), leftAction.toByte())
-        )
-    }
-
-    /**
-     * 操作钥匙/便携式底座钥匙卡扣,一次只操作一个卡扣
-     *
-     * @param isOpen true:开操作 false:关操作
-     * @param index 0:左 1:右 便携式底座钥匙传0
-     */
-    fun generateKeyBuckleCmd(isOpen: Boolean, index: Int): MBFrame {
-        return MBFrame(
-            FRAME_TYPE_WRITE,
-            byteArrayOf(0x00, 0x11, if (index == 1) 0b00010000.toByte() else 0b0000001, if (isOpen) 0x00 else 0xFF.toByte())
-        )
-    }
-
-    /**
-     * 生成RFID 读指令
-     *
-     * @param idx 锁具底座锁具:0-9  钥匙底座钥匙:0(left)-1(right)  便携式底座锁具:0-2  便携式底座钥匙:4   便携式底座卡:8
-     */
-    fun generateRfidCmd(idx: Int): MBFrame {
-        return MBFrame(
-            FRAME_TYPE_READ,
-            byteArrayOf(0x00, (0x20 + idx * 4).toByte(), 0x00, 0x04)
-        )
-    }
-}
-
-
-class FrameTask(
-    val req: ByteArray,
-    val done: ((res: ByteArray) -> Unit)?    // 响应回调
-) {
-
-    /**
-     * 是否允许重发
-     */
-    var allowRetransmission: Boolean = true
-
-    /**
-     * 上次发送时间
-     */
-    var lastSent: Long = 0
-
-    /**
-     * 已发送次数
-     */
-    var sentCount = 0
-
-    /**
-     * 最小发送间隔
-     */
-    var minSendInterval: Int = MODBUS_MIN_SEND_INTERVAL
-
-
-    fun waitIfNecessary() {
-        val interval = System.nanoTime() - lastSent
-        if (interval < minSendInterval) {
-            Thread.sleep((minSendInterval - interval) / 1000_000)
-        }
-    }
-
-    fun shouldSend(): Boolean {
-        return if (allowRetransmission) {
-            sentCount < 3
-        } else {
-            sentCount < 1
-        }
-    }
-
-    fun afterSent() {
-        sentCount++
-        lastSent = System.nanoTime()
-    }
-
-    /**
-     * 判断 res 是否是 frame 的响应
-     */
-    fun match(res: ByteArray): Boolean {
-        // 从机地址 和 功能码 必须相同
-        if (res.size < 5 || req[0] != res[0] || req[1] != res[1]) {
-            return false
-        }
-        // 报文2 的 CRC校验得正确
-        val crc16 = res.crc16(0, res.size - 2)
-        return crc16[0] == res[res.size - 2] && crc16[1] == res[res.size - 1]
-    }
-
-}
-
-private const val FRAME_TYPE_READ: Byte = 0x03
-private const val FRAME_TYPE_WRITE: Byte = 0x06
-private const val FRAME_TYPE_SCANNER: Byte = 0x43
-const val FRAME_TYPE_WRITE_MULTI: Byte = 0x10
-const val FRAME_TYPE_WRITE_FILE: Byte = 0x15
-
-/**
- * ModBus 数据帧
- */
-class MBFrame(
-
-    // 类型
-    val type: Byte,
-    // 数据域:D1 和 D2
-    val data: ByteArray
-
-) {
-
-    /**
-     * @param index 从机序号
-     */
-    fun compile(index: Int): ByteArray {
-        val bytes = ByteArray(4 + data.size)
-        // TODO 从机开始地址0x01
-//        bytes[0] = (0x80 + index).toByte()
-        bytes[0] = (1 + index).toByte()
-        bytes[1] = type
-        for (i in data.indices) {
-            bytes[2 + i] = data[i]
-        }
-        val crc16 = bytes.crc16(0, bytes.size - 2)
-        bytes[bytes.size - 2] = crc16[0]
-        bytes[bytes.size - 1] = crc16[1]
-        return bytes
-
-//        val cmd = byteArrayOf((1 + index).toByte()) + byteArrayOf(type) + data
-//        return cmd + cmd.crc16()
-    }
-
-    /**
-     * @param address 从机地址
-     */
-    fun compile(address: Byte): ByteArray {
-        val bytes = ByteArray(4 + data.size)
-        bytes[0] = address
-        bytes[1] = type
-        for (i in data.indices) {
-            bytes[2 + i] = data[i]
-        }
-        val crc16 = bytes.crc16(0, bytes.size - 2)
-        bytes[bytes.size - 2] = crc16[0]
-        bytes[bytes.size - 1] = crc16[1]
-        return bytes
-    }
-
-    companion object {
-        /**
-         * 读取设备类型
-         */
-        val READ_DEVICE_TYPE = MBFrame(
-            FRAME_TYPE_READ,
-            byteArrayOf(0x00, 0x00, 0x00, 0x01)
-        )
-
-        /**
-         * 读钥匙/锁具/便携式底座状态
-         */
-        val READ_STATUS = MBFrame(
-            FRAME_TYPE_READ,
-            byteArrayOf(0x00, 0x10, 0x00, 0x01)
-        )
-
-        /**
-         * 读卡扣状态(钥匙、锁的0-7、便携式的锁和钥匙)
-         */
-        val READ_BUCKLE_STATUS = MBFrame(
-            FRAME_TYPE_READ,
-            byteArrayOf(0x00, 0x11, 0x00, 0x01)
-        )
-
-        /**
-         * 读卡扣状态(锁的9、10)
-         */
-        val READ_LOCK_BUCKLE_EXTRA_STATUS = MBFrame(
-            FRAME_TYPE_READ,
-            byteArrayOf(0x00, 0x12, 0x00, 0x01)
-        )
-    }
 }

+ 10 - 0
app/src/main/java/com/grkj/iscs/modbus/StatusListener.kt

@@ -0,0 +1,10 @@
+package com.grkj.iscs.modbus
+
+/**
+ * 状态监听器
+ */
+class StatusListener(
+    val key: Any,
+    val listener: (MBFrame, Any) -> Unit,
+    val type: Int
+)

+ 4 - 4
app/src/main/java/com/grkj/iscs/view/fragment/DeviceStatusFragment.kt

@@ -122,14 +122,14 @@ class DeviceStatusFragment :
             holder?.getView<View>(R.id.v_buckle_status_2)?.backgroundTintList =
                 if (presenter?.getKeyBuckleLockEnabled(
                         row.dockList.find { it.column == "1" }?.address,
-                        true
+                        false
                     ) == true
                 ) ColorStateList.valueOf(statusCloseTintColor) else ColorStateList.valueOf(
                     statusOpenTintColor
                 )
             holder?.getView<View>(R.id.v_buckle_status_3)?.backgroundTintList =
                 if (presenter?.getKeyBuckleLockEnabled(
-                        row.dockList.find { it.column == "1" }?.address,
+                        row.dockList.find { it.column == "2" }?.address,
                         true
                     ) == true
                 ) ColorStateList.valueOf(statusCloseTintColor) else ColorStateList.valueOf(
@@ -137,8 +137,8 @@ class DeviceStatusFragment :
                 )
             holder?.getView<View>(R.id.v_buckle_status_4)?.backgroundTintList =
                 if (presenter?.getKeyBuckleLockEnabled(
-                        row.dockList.find { it.column == "1" }?.address,
-                        true
+                        row.dockList.find { it.column == "2" }?.address,
+                        false
                     ) == true
                 ) ColorStateList.valueOf(statusCloseTintColor) else ColorStateList.valueOf(
                     statusOpenTintColor

+ 2 - 2
app/src/main/res/layout/item_rv_lock_dock_child_status.xml

@@ -7,8 +7,8 @@
 
     <FrameLayout
         android:id="@+id/root"
-        android:layout_width="30dp"
-        android:layout_height="90dp"
+        android:layout_width="20dp"
+        android:layout_height="70dp"
         android:background="@drawable/dock_lock_selector" />
 
     <LinearLayout

+ 1 - 0
app/src/main/res/layout/item_rv_lock_dock_status.xml

@@ -14,5 +14,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_centerHorizontal="true"
+        android:paddingVertical="@dimen/common_rv_tab_padding"
         android:orientation="horizontal" />
 </RelativeLayout>

+ 1 - 1
app/src/main/res/values/dimens.xml

@@ -14,7 +14,7 @@
     <dimen name="common_icon_size">15dp</dimen>
     <dimen name="common_icon_size_small">12dp</dimen>
     <dimen name="common_status_circle_small">5dp</dimen>
-    <dimen name="common_status_circle_medium">15dp</dimen>
+    <dimen name="common_status_circle_medium">10dp</dimen>
 
     <dimen name="common_btn_width">150dp</dimen>
     <dimen name="common_btn_height">50dp</dimen>