package com.grkj.iscs.modbus import android.content.Context import com.clj.fastble.BleManager import com.grkj.iscs.BusinessManager import com.grkj.iscs.BusinessManager.CAN_RETURN import com.grkj.iscs.R import com.grkj.iscs.extentions.removeLeadingZeros import com.grkj.iscs.extentions.toHexStrings import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_CARD import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_FINGERPRINT import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_KEY import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_LOCK import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_COLLECT import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_ELEC_LOCK_BOARD import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_KEY import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_LOCK import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_PORTABLE import com.grkj.iscs.model.vo.hardware.CabinetSlotsRecord import com.grkj.iscs.util.CommonUtils import com.grkj.iscs.util.Executor import com.grkj.iscs.util.NetApi import com.grkj.iscs.util.ToastUtils import com.grkj.iscs.util.log.LogUtil import java.util.concurrent.atomic.AtomicInteger import java.util.stream.Collectors /** * ModBus 主控板控制器 */ object ModBusController { /** * 是否初始化完成 */ var isInitReady = false /** * 底座列表 */ var dockList: MutableList = mutableListOf() /** * 监听状态类型 */ private const val LISTENER_TYPE_STATUS = 3 // 主控板管理器 var modBusManager: ModBusManager? = null /** * 监听器 */ private val listeners = ArrayList() // 是否中断读取状态 private var interruptReadStatus: ArrayList = ArrayList() /** * 重复时间 */ // TODO 临时改成5s const val REPEAT_FREQUENCY = 800L /** * 中断读取 */ fun interruptReadTrashBinStatus(interrupt: Boolean) { interruptReadStatus.clear() interruptReadStatus.add(interrupt) } /** * 启动通信引擎 */ @ExperimentalUnsignedTypes fun start(ctx: Context) { modBusManager?.stop() PortManager.openCtrlBord(ctx)?.let { pm -> return@let ModBusManager(pm, true) } // 间隔 1 秒读一遍桶的状态 ?.repeatSendToAll(MBFrame.READ_STATUS, { interruptReadStatus }, { res -> LogUtil.i("****************************************************************************") // 过滤非空的数据,重置slaveCount // 不再使用slaveCount,改用地址池 for (l in listeners) { if (l.type == LISTENER_TYPE_STATUS) { l.listener(res) } } }, REPEAT_FREQUENCY)?.also { modBusManager = it }?.start() } /** * 注册监听器 */ fun registerStatusListener(key: Any, listener: (Any) -> Unit) { listeners.add(StatusListener(key, listener, LISTENER_TYPE_STATUS)) } /** * 取消注册监听器 */ fun unregisterListener(key: Any) { val it = listeners.iterator() while (it.hasNext()) { if (it.next().key == key) { it.remove() } } } /** * 停止引擎 */ fun stop() { modBusManager?.stop() } /** * 引擎是否运行中 */ fun isRunning(): Boolean? { return modBusManager?.isRunning() } /*****************************************************************************************/ /** * 初始化所有设备的状态 */ fun initDevicesStatus() { readDeviceType { res -> res.forEach { bytes -> if (bytes.size < 5) return@forEach // 设备具体数据由0x0011寄存器提供 updateDeviceType(bytes[0], bytes[4]) val type = when (bytes[4]) { DOCK_TYPE_KEY -> "钥匙底座" DOCK_TYPE_LOCK -> "锁具底座" DOCK_TYPE_ELEC_LOCK_BOARD -> "电磁锁控制板" DOCK_TYPE_PORTABLE -> "便携式底座" DOCK_TYPE_COLLECT -> "开关量采集板" else -> "未知" } LogUtil.i("initDevicesStatus 设备(${bytes[0].toInt()})类型:$type") } // TODO 待完善 Executor.repeatOnMain({ if (isInitReady) { initLock() // 打开所有无锁的卡扣、关闭所有有锁的卡扣、读取所有锁的RFID initKey() // 打开所有无钥匙的卡扣、关闭所有有钥匙的卡扣、读取所有钥匙的RFID return@repeatOnMain false } else { return@repeatOnMain true } }, REPEAT_FREQUENCY, true) } } /** * 初始化锁具——打开所有无锁的卡扣、读取RFID */ private fun initLock() { LogUtil.i("initLock : $dockList") dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE } .forEach { dockBean -> val hasLockIdxList = dockBean.getLockList().filter { it.isExist }.map { it.idx } as MutableList val noLockIdxList = dockBean.getLockList().filter { !it.isExist }.map { it.idx } as MutableList hasLockIdxList.forEach { idx -> readLockRfid(dockBean.addr, idx) { res -> if (res.size < 11) { LogUtil.e("Lock rfid error") return@readLockRfid } val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros() LogUtil.i("初始化锁具 RFID : $rfid") updateLockRfid(dockBean.addr, idx, rfid) NetApi.getLockInfo(rfid) { updateLockNewHardware(dockBean.addr, idx, it == null) } } } controlLockBuckle(false, dockBean.addr, hasLockIdxList) controlLockBuckle(true, dockBean.addr, noLockIdxList) } } /** * 初始化钥匙 */ private fun initKey() { LogUtil.i("initKey : $dockList") dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE } .forEach { dockBean -> dockBean.getKeyList().forEach { key -> if (key.isExist) { LogUtil.i("initKey : ${dockBean.addr} : ${key.isLeft}") readKeyRfid(dockBean.addr, if (key.isLeft) 0 else 1) { isLeft, res -> if (res.size < 11) { LogUtil.e("Key rfid error") return@readKeyRfid } val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros() LogUtil.i("初始化钥匙 RFID : $rfid") // 更新rfid updateKeyRfid(dockBean.addr, isLeft, rfid) // 蓝牙准备操作 NetApi.getKeyInfo(rfid) { LogUtil.i("getKeyInfo : $rfid - ${it?.macAddress}") updateKeyNewHardware(dockBean.addr, isLeft, it == null) if (it != null && !it.macAddress.isNullOrEmpty()) { // 更新mac updateKeyMac(dockBean.addr, key.isLeft, it.macAddress) BusinessManager.registerConnectListener( it.macAddress, false ) { isDone, bleBean -> if (isDone && bleBean?.bleDevice != null) { Executor.delayOnMain(500) { BusinessManager.getCurrentStatus( 3, bleBean.bleDevice ) } } } } else { ToastUtils.tip(R.string.get_key_info_fail) } } } controlKeyBuckle(false, key.isLeft, dockBean.addr) } else { controlKeyBuckle(true, key.isLeft, dockBean.addr) } } } } /** * 获取最新状态 */ fun updateStatus(byteArray: ByteArray): DockBean? { if (byteArray.isEmpty()) { return null } val dockB = dockList.find { it.addr == byteArray[0] } return dockB?.parseStatus(byteArray) } /** * 更新所有锁仓状态 */ fun updateAllBuckleStatus(done: () -> Unit) { val remaining = AtomicInteger(2) modBusManager?.sendToAll(MBFrame.READ_BUCKLE_STATUS) { res -> LogUtil.i("****************************************************************************") // 过滤非空的数据,重置slaveCount // 不再使用slaveCount,改用地址池 lockBuckleStatus(res) // 每完成一个就把计数减一,减到 0 就触发 done() if (remaining.decrementAndGet() == 0) { done() } } modBusManager?.sendToAll(MBFrame.READ_LOCK_BUCKLE_EXTRA_STATUS) { res -> LogUtil.i("****************************************************************************") // 过滤非空的数据,重置slaveCount // 不再使用slaveCount,改用地址池 lockBuckleExtraStatus(res) // 每完成一个就把计数减一,减到 0 就触发 done() if (remaining.decrementAndGet() == 0) { done() } } } /** * 更新开关状态 */ fun updateSwitchStatus(done: () -> Unit) { modBusManager?.mSlaveAddressList?.find { it == (0xA1).toByte() }?.let { modBusManager?.sendTo(it, MBFrame.READ_BUCKLE_STATUS) { res -> LogUtil.i("****************************************************************************") // 过滤非空的数据,重置slaveCount // 不再使用slaveCount,改用地址池 switchStatus(res, done) } } } /** * 第9,10锁位卡扣状态 */ private fun lockBuckleExtraStatus(res: Any) { LogUtil.i("硬件状态:${(res as List).map { it.toHexStrings() }}") if (res.isEmpty() || res.any { it.isEmpty() }) { var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : " val addressList = mutableListOf() modBusManager?.mSlaveAddressList?.forEach { itDock -> if (res.none { it.isNotEmpty() && it[0] == itDock }) { addressList.add("0x${String.format("%02X", itDock)}") } } tipStr += addressList ToastUtils.tip(tipStr) } res.forEach { bytes -> val dockBean = updateExtraLockStatus(bytes) ?: return@forEach if (!CAN_RETURN) { return@forEach } when (dockBean.type) { DOCK_TYPE_LOCK -> { dockBean.getLockList().filter { it.idx > 7 }.forEach { lockBean -> updateLockStatus( dockBean.addr, lockBean.idx, lockBean.lockEnabled ) } } } } } /** * 开关量更新 */ private fun switchStatus(res: Any, done: () -> Unit) { LogUtil.i("开关板:${(res as ByteArray).toHexStrings()}") if (res.isEmpty()) { var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : " val addressList = mutableListOf() modBusManager?.mSlaveAddressList?.forEach { itDock -> if (res.isNotEmpty() && res == itDock) { addressList.add("0x${String.format("%02X", itDock)}") } } tipStr += addressList ToastUtils.tip(tipStr) } updateSwitchStatus(res, done) } /** * 第1-8锁位卡扣状态和钥匙 */ private fun lockBuckleStatus(res: Any) { LogUtil.i("硬件状态:${(res as List).map { it.toHexStrings() }}") if (res.isEmpty() || res.any { it.isEmpty() }) { var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : " val addressList = mutableListOf() modBusManager?.mSlaveAddressList?.forEach { itDock -> if (res.none { it.isNotEmpty() && it[0] == itDock }) { addressList.add("0x${String.format("%02X", itDock)}") } } tipStr += addressList ToastUtils.tip(tipStr) } res.forEach { bytes -> val dockBean = updateLockStatus(bytes) ?: return@forEach if (!CAN_RETURN) { return@forEach } when (dockBean.type) { DOCK_TYPE_KEY -> { dockBean.getKeyList().forEach { keyBean -> updateKeyLockStatus( dockBean.addr, keyBean.isLeft, keyBean.lockEnabled ) //todo 更新锁仓状态 } } DOCK_TYPE_LOCK -> { dockBean.getLockList().forEach { lockBean -> updateLockStatus( dockBean.addr, lockBean.idx, lockBean.lockEnabled ) } } DOCK_TYPE_ELEC_LOCK_BOARD -> { // TODO 占位 } DOCK_TYPE_PORTABLE -> { // TODO 便携式待完善 dockBean.deviceList.forEach { deviceBean -> if (deviceBean.isExist) { when (deviceBean.type) { DEVICE_TYPE_KEY -> { updateKeyLockStatus( dockBean.addr, true, deviceBean.lockEnabled ) } DEVICE_TYPE_LOCK -> { updateLockStatus( dockBean.addr, deviceBean.idx, deviceBean.lockEnabled ) } DEVICE_TYPE_CARD -> { readPortalCaseCardRfid(dockBean.addr) { res -> if (res.size < 11) { LogUtil.e("Portal Case card rfid error") return@readPortalCaseCardRfid } val rfid = res.copyOfRange(3, 11).toHexStrings(false) .removeLeadingZeros() LogUtil.i("卡片RFID : $rfid") } } DEVICE_TYPE_FINGERPRINT -> { } } } } } } } } /** * 获取第1-8的锁仓数据和左右钥匙数据 */ private fun updateLockStatus(byteArray: ByteArray): DockBean? { if (byteArray.isEmpty()) { return null } val dockB = dockList.find { it.addr == byteArray[0] } return dockB?.parseLockStatus(byteArray) } /** * 更新开关状态 */ private fun updateSwitchStatus(byteArray: ByteArray, done: () -> Unit): DockBean? { if (byteArray.isEmpty()) { return null } val dockB = dockList.find { it.addr == byteArray[0] } return dockB?.parseSwitchStatus(byteArray, done) } /** * 获取额外的9,10锁仓数据 */ private fun updateExtraLockStatus(byteArray: ByteArray): DockBean? { if (byteArray.isEmpty()) { return null } val dockB = dockList.find { it.addr == byteArray[0] && it.type == DOCK_TYPE_LOCK } return dockB?.parseExtraLockStatus(byteArray) } /** * 读取设备类型 */ private fun readDeviceType(done: ((res: List) -> Unit)? = null) { modBusManager?.sendToAll(MBFrame.READ_DEVICE_TYPE) { res -> done?.invoke(res) } } /** * 更新设备类型 */ private fun updateDeviceType(idx: Byte, type: Byte?) { val dock = dockList.find { it.addr == idx } dock?.let { it.type = type } ?: let { dockList.add(DockBean(idx, type, true, mutableListOf())) } } /** * 读取卡扣状态 * * @param isLock true:读锁具底座 false:读钥匙底座 * @param type 0:钥匙底座 1:锁具底座1-8 2:锁具底座9、10 */ fun readBuckleStatus( isLock: Boolean, slaveAddress: Byte?, doneSingle: ((type: Int, res: ByteArray) -> Unit)? = null ) { // TODO 电磁锁控制板可能不是,并且锁和钥匙的读取不一样 slaveAddress?.let { modBusManager?.sendTo(it, MBFrame.READ_BUCKLE_STATUS) { res -> doneSingle?.invoke(if (isLock) 1 else 0, res) } if (isLock) { modBusManager?.sendTo(it, MBFrame.READ_LOCK_BUCKLE_EXTRA_STATUS) { res -> doneSingle?.invoke(2, res) } } } } /** * 开/关锁具卡扣 单 */ fun controlLockBuckle( isOpen: Boolean, slaveAddress: Byte?, lockIdx: Int, done: ((res: ByteArray) -> Unit)? = null ) { slaveAddress?.let { ModBusCMDHelper.generateLockBuckleCmd(isOpen, lockIdx)?.let { cmd -> modBusManager?.sendTo(it, cmd) { res -> done?.invoke(res) } } } } /** * 开/关锁具卡扣 多 */ fun controlLockBuckle( isOpen: Boolean, slaveAddress: Byte?, lockIdxList: MutableList, done: ((res: ByteArray) -> Unit)? = null ) { slaveAddress?.let { ModBusCMDHelper.generateLockBuckleCmd(isOpen, lockIdxList)?.let { cmdList -> cmdList.forEach { cmd -> modBusManager?.sendTo(it, cmd) { res -> done?.invoke(res) } } } } } /** * 读取钥匙RFID */ fun readKeyRfid( slaveAddress: Byte?, idx: Int, done: ((isLeft: Boolean, res: ByteArray) -> Unit)? = null ) { slaveAddress?.let { ModBusCMDHelper.generateRfidCmd(idx)?.let { cmd -> modBusManager?.sendTo(it, cmd) { done?.invoke(idx == 0, it) } } } } /** * 读取锁具RFID */ fun readLockRfid(slaveAddress: Byte?, lockIdx: Int, done: ((res: ByteArray) -> Unit)? = null) { slaveAddress?.let { ModBusCMDHelper.generateRfidCmd(lockIdx)?.let { cmd -> modBusManager?.sendTo(it, cmd) { res -> done?.invoke(res) } } } } /** * 读便携式底座卡RFID */ fun readPortalCaseCardRfid(slaveAddress: Byte?, done: ((res: ByteArray) -> Unit)? = null) { slaveAddress?.let { ModBusCMDHelper.generateRfidCmd(8)?.let { cmd -> modBusManager?.sendTo(it, cmd) { res -> done?.invoke(res) } } } } /** * 更新钥匙RFID */ fun updateKeyRfid(slaveAddress: Byte, isLeft: Boolean, rfid: String) { dockList.find { it.addr == slaveAddress }?.getKeyList() ?.find { it.isLeft == isLeft }?.rfid = rfid } /** * 更新钥匙锁仓状态 */ private fun updateKeyLockStatus(slaveAddress: Byte, isLeft: Boolean, lockEnabled: Boolean) { dockList.find { it.addr == slaveAddress }?.getKeyList() ?.find { it.isLeft == isLeft }?.lockEnabled = lockEnabled } /** * 更新钥匙MAC */ fun updateKeyMac(slaveAddress: Byte, isLeft: Boolean, mac: String) { dockList.find { it.addr == slaveAddress }?.getKeyList()?.find { it.isLeft == isLeft }?.mac = mac } /** * 更新钥匙时候为新设备 */ fun updateKeyNewHardware(slaveAddress: Byte, isLeft: Boolean, newHardware: Boolean) { dockList.find { it.addr == slaveAddress }?.getKeyList() ?.find { it.isLeft == isLeft }?.newHardware = newHardware } /** * 更新锁具RFID */ fun updateLockRfid(slaveAddress: Byte, lockIdx: Int, rfid: String) { dockList.find { it.addr == slaveAddress }?.getLockList()?.find { it.idx == lockIdx }?.rfid = rfid } /** * 更新锁是不是新设备,就是后台没有数据的 */ fun updateLockNewHardware(slaveAddress: Byte, lockIdx: Int, newHardware: Boolean) { dockList.find { it.addr == slaveAddress }?.getLockList() ?.find { it.idx == lockIdx }?.newHardware = newHardware } /** * 更新锁仓状态 */ fun updateLockStatus(slaveAddress: Byte, lockIdx: Int, lockEnabled: Boolean) { dockList.find { it.addr == slaveAddress }?.getLockList() ?.find { it.idx == lockIdx }?.lockEnabled = lockEnabled } /** * 控制钥匙卡扣 */ fun controlKeyBuckle(isOpen: Boolean, mac: String, done: ((res: ByteArray) -> Unit)? = null) { val dockBean = getDockByKeyMac(mac) dockBean ?: return val key = getKeyByMac(mac) key ?: return controlKeyBuckle(isOpen, key.isLeft, dockBean.addr, done) } /** * 开/关钥匙卡扣 * * @param isOpen true:开操作 false:关操作 * @param isLeft true:左卡扣 false:右卡扣 */ fun controlKeyBuckle( isOpen: Boolean, isLeft: Boolean, slaveAddress: Byte?, done: ((res: ByteArray) -> Unit)? = null ) { slaveAddress?.let { ModBusCMDHelper.generateKeyBuckleCmd(isOpen, if (isLeft) 0 else 1)?.let { cmd -> modBusManager?.sendTo(it, cmd) { res -> done?.invoke(res) } } } } /** * 根据RFID找钥匙 */ fun getKeyByRfid(rfid: String): DockBean.KeyBean? { return dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE } .flatMap { it.getKeyList() }.find { it.rfid == rfid } } /** * 根据Mac找钥匙 */ fun getKeyByMac(mac: String): DockBean.KeyBean? { return dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE } .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 } } /** * 钥匙是否存在 */ fun isKeyExist(dockAddr: Byte?, isLeft: Boolean): Boolean { dockAddr ?: return false return dockList.find { it.addr == dockAddr }?.getKeyList() ?.find { it.isLeft == isLeft && it.isExist } != null } /** * 获取钥匙锁仓的锁定状态 */ fun getKeyBuckleLockEnabled(dockAddr: Byte?, isLeft: Boolean): Boolean { dockAddr ?: return false return dockList.find { it.addr == dockAddr }?.getKeyList() ?.find { it.isLeft == isLeft }?.lockEnabled == true } /** * 获取挂锁锁仓的锁定状态 */ fun getLockBuckleLockEnabled(dockAddr: Byte?, lockIdx: Int): Boolean { dockAddr ?: return false return dockList.find { it.addr == dockAddr }?.getLockList() ?.find { it.idx == lockIdx }?.lockEnabled == true } /** * 获取挂锁是否存在 */ fun isLockExist(dockAddr: Byte?, lockIdx: Int): Boolean { dockAddr ?: return false return dockList.find { it.addr == dockAddr }?.getLockList() ?.find { it.idx == lockIdx && it.isExist } != null } /** * 获取钥匙状态 * * @return 0:不存在 1:存在 2:有RFID 3:有MAC 4:连接上 5:待机模式 6: 待机模式无异常 */ fun getKeyStatus(dockAddr: Byte?, isLeft: Boolean): Int { dockAddr ?: return 0 val key = dockList.find { it.addr == dockAddr }?.getKeyList()?.find { it.isLeft == isLeft } LogUtil.i("getKeyStatus key : $key") key ?: return 0 var status = 0 if (key.isExist) { status = 1 } else { return status } if (key.rfid != null) { status = 2 } else { return status } if (key.mac != null) { status = 3 } else { return status } if (BleManager.getInstance() .isConnected(BusinessManager.getBleDeviceByMac(key.mac)?.bleDevice) ) { status = 4 } else { return status } if (key.isReady) { status = 5 } else { return status } if (key.rfid != null && BusinessManager.mExceptionKeyList.none { it == key.rfid }) { status = 6 } else { return status } return status } /** * 更新钥匙的准备状态 */ fun updateKeyReadyStatus(mac: String, isReady: Boolean, from: Int) { LogUtil.i("updateKeyReadyStatus mac : $mac - $isReady - $from") dockList.forEach { if (it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE) { if (it.getKeyList().any { it.mac == mac }) { it.getKeyList().find { it.mac == mac }?.isReady = isReady } } } } /** * 根据钥匙Mac获取底座 */ fun getDockByKeyMac(mac: String): DockBean? { return dockList.find { (it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE) && it.getKeyList() .any { it.mac == mac } } } /** * 根据类型获取底座列表 */ fun getDockByType(type: Byte): List { return dockList.filter { it.type == type } } /** * 根据底座类型获取钥匙列表 */ fun getKeyByDockType(type: Byte): MutableList? { 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 -> val list = dockBean.getLockList().stream().map { it.idx }.collect(Collectors.toList()) controlLockBuckle(isOpen, dockBean.addr, list) { LogUtil.i("${if (isOpen) "开启" else "关闭"}所有锁卡扣 : ${it.toHexStrings()}") } } } /** * 打印全部底座信息 */ fun printDockInfo() { LogUtil.i("当前底座列表 : $dockList") dockList.forEach { dockBean -> when (dockBean.type) { DOCK_TYPE_LOCK -> { dockBean.getLockList().forEach { lockBean -> LogUtil.i("${dockBean.addr}锁${lockBean.idx} : ${lockBean.rfid}") } } DOCK_TYPE_KEY -> { dockBean.getKeyList().forEach { keyBean -> LogUtil.i("${dockBean.addr}钥${keyBean.idx} : ${keyBean.rfid}") } } DOCK_TYPE_PORTABLE -> { dockBean.getLockList().forEach { lockBean -> LogUtil.i("${dockBean.addr}柜锁${lockBean.idx} : ${lockBean.rfid}") } dockBean.getKeyList().forEach { keyBean -> LogUtil.i("${dockBean.addr}柜钥${keyBean.idx} : ${keyBean.rfid}") } } } } } /** * 更新设备类型 */ fun updateDeviceType() { LogUtil.i("____________________________________") readDeviceType { res -> LogUtil.i("设备类型数量 : ${res.size}") LogUtil.i("设备类型 : ${res.map { it.toHexStrings() }}") res.forEach { bytes -> if (bytes.size < 5) return@forEach // 设备具体数据由0x0011寄存器提供 updateDeviceType(bytes[0], bytes[4]) val type = when (bytes[4]) { DOCK_TYPE_KEY -> "钥匙底座" DOCK_TYPE_LOCK -> "锁具底座" DOCK_TYPE_ELEC_LOCK_BOARD -> "电磁锁控制板" DOCK_TYPE_PORTABLE -> "便携式底座" else -> "未知" } LogUtil.i("设备(${bytes[0].toInt()})类型:$type") } LogUtil.i("____________________________________") } } /** * 随机获取一个钥匙(存在的、有RFID、有Mac、连接的、是待机模式的) * * @return 底座地址,钥匙 */ fun getOneKey( exceptionSlots: MutableList, exceptionKeys: MutableList ): Pair? { val keyDockList = dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE } keyDockList.sortedBy { it.addr } keyDockList.forEach { it.deviceList.sortedBy { it.idx } } val keyList = keyDockList.map { it.deviceList }.flatten() .filterIsInstance() .filterIndexed { index, _ -> (index + 1) !in exceptionSlots.map { it.col?.toInt() } } .filter { it.rfid !in exceptionKeys && !it.rfid.isNullOrEmpty() && !it.mac.isNullOrEmpty() && it.isExist } .toMutableList() LogUtil.i("keyList : $keyList") if (keyList.isEmpty()) { ToastUtils.tip(R.string.no_available_key) return null } keyList.forEach { LogUtil.i( "keyStatus 满足条件的钥匙: ${it.isExist} - ${it.rfid} - ${it.mac} - ${it.isReady} - " + "${ BusinessManager.getBleDeviceByMac( it.mac )?.bleDevice != null } - " + "${ BleManager.getInstance() .isConnected(BusinessManager.getBleDeviceByMac(it.mac)?.bleDevice) } - " + "${!BusinessManager.mExceptionKeyList.contains(it.rfid)}" ) } val key = keyList.filter { it.isExist && it.rfid != null && it.mac != null && it.isReady && BleManager.getInstance() .isConnected(BusinessManager.getBleDeviceByMac(it.mac)?.bleDevice) && !BusinessManager.mExceptionKeyList.contains( it.rfid ) }.shuffled().firstOrNull() if (key == null) { LogUtil.e("getOneKey : no key match") return null } val address = keyDockList.find { it.getKeyList().any { it.rfid == key.rfid } }?.addr if (address == null) { LogUtil.e("getOneKey : no dock match") return null } return Pair(address, key) } /** * 根据数量获取锁具(基于锁柜和便携柜不存在接一起的情况) * * @param needLockCount 需要打开的锁具数量 * * @return key: dock地址,value: 锁具RFID列表 */ fun getLocks( needLockCount: Int, exceptionSlots: MutableList, exceptionLocks: MutableList ): MutableMap> { val map = mutableMapOf>() if (needLockCount == 0) { return map } val lockDockList = dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE } lockDockList.sortedBy { it.addr } var provideCount = 0 for (lockDockIndex in lockDockList.indices) { if (provideCount >= needLockCount) break val validLocks = lockDockList[lockDockIndex].getLockList().filter { it.rfid !in exceptionLocks } .filter { it.isExist && it.idx !in exceptionSlots.filter { it.row?.toInt() == (lockDockIndex + 1) } .map { (it.col?.toInt() ?: 1) - 1 } } val toTake = (needLockCount - provideCount).coerceAtMost(validLocks.size) if (toTake > 0) { map[lockDockList[lockDockIndex].addr] = validLocks.take(toTake).toMutableList() provideCount += toTake } } return map } /** * 获取开关量数据 */ fun getSwitchData(): MutableList { return dockList.filter { it.type == DOCK_TYPE_COLLECT }.sortedBy { it.addr } .flatMap { it.getSwitchList() }.mapIndexed { index, switchBean -> DockBean.SwitchBean(index, switchBean.switchBoardAddr, switchBean.enabled) }.toMutableList() } /** * 读取开关采集板数据 */ fun readSwitchStatus( slaveAddress: Byte?, addr: ByteArray, done: ((res: ByteArray) -> Unit)? = null ) { slaveAddress?.let { ModBusCMDHelper.generateSwitchBoardStatusCmd(addr)?.let { cmd -> modBusManager?.sendTo(it, cmd) { res -> done?.invoke(res) } } } } }