package com.grkj.iscs.modbus import android.content.Context import com.grkj.iscs.R import com.grkj.iscs.extentions.removeLeadingZeros import com.grkj.iscs.extentions.toHexStrings 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.util.Executor import com.grkj.iscs.util.ToastUtils import com.grkj.iscs.util.log.LogUtil import java.util.concurrent.Executors import java.util.stream.Collectors /** * ModBus 主控板控制器 */ object ModBusController { /** * 底座列表 */ var dockList: MutableList = mutableListOf() private const val LISTENER_TYPE_STATUS = 3 // 主控板管理器 private var modBusManager: ModBusManager? = null private var slaveCount: Int = 0 private val threadPool = Executors.newScheduledThreadPool(4) private val listeners = ArrayList() // 是否中断读取状态 private var interruptReadStatus: ArrayList = ArrayList() var shouldStopUpgrade = false // TODO 临时改成5s const val REPEAT_FREQUENCY = 800L fun setSlaveCount(count: Int) { modBusManager?.slaveCount = count slaveCount = count } class StatusListener( val key: Any, val listener: (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) } // 间隔 1 秒读一遍桶的状态 ?.repeatSendToAll(MBFrame.READ_STATUS, { interruptReadStatus }, { res -> // // Logger.d("ModbusController", "res: ${res.map { it.toHexString() }}") LogUtil.i("****************************************************************************") for (l in listeners) { if (l.type == LISTENER_TYPE_STATUS) { l.listener(res) } } }, REPEAT_FREQUENCY) ?.also { modBusManager = it Executor.runOnIO { // refreshAllowOpenDoorUnidentified(ctx, 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() } /*****************************************************************************************/ /** * 初始化所有设备的状态 */ // TODO 通电后多久执行?App每次重启的执行是什么 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 -> "便携式底座" else -> "未知" } LogUtil.i("initDevicesStatus 设备(${bytes[0].toInt()})类型:$type") // TODO 待完善 Executor.delayOnMain(REPEAT_FREQUENCY) { initLock() // 打开所有无锁的卡扣、关闭所有有锁的卡扣、读取所有锁的RFID initKey() // 打开所有无钥匙的卡扣、关闭所有有钥匙的卡扣、关闭所有钥匙灯光、读取所有钥匙的RFID } // TODO 设置所有钥匙的模式 // TODO 通过HTTP获取所有钥匙的Mac } } } /** * 初始化锁具——打开所有无锁的卡扣、读取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.toInt() - 1, idx) { res -> val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros() LogUtil.i("初始化锁具 RFID : $rfid") updateLockRfid(dockBean.addr.toInt(), idx, rfid) } } controlLockBuckle(false, dockBean.addr.toInt() - 1, hasLockIdxList) controlLockBuckle(true, dockBean.addr.toInt() - 1, noLockIdxList) } } /** * 初始化钥匙——关闭所有钥匙灯光 */ private fun initKey() { LogUtil.i("initKey : $dockList") dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }.forEach { dockBean -> controlKeyLight(dockBean.addr.toInt() - 1, 2, 2) dockBean.getKeyList().forEach { key -> if (key.isExist) { LogUtil.i("initKey : ${dockBean.addr.toInt() - 1} : ${key.isLeft}") readKeyRfid(dockBean.addr.toInt() - 1, if (key.isLeft) 0 else 1) { isLeft, res -> val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros() LogUtil.i("初始化钥匙 RFID : $rfid") updateKeyRfid(dockBean.addr.toInt(), isLeft, rfid) } controlKeyBuckle(false, key.isLeft, dockBean.addr.toInt() - 1) } else { controlKeyBuckle(true, key.isLeft, dockBean.addr.toInt() - 1) } } } } /** * 更新状态 */ fun updateStatus(byteArray: ByteArray): DockBean? { if (byteArray.isEmpty()) { return null } val dockB = dockList.find { it.addr == byteArray[0] } return dockB?.parseStatus(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, mutableListOf())) } } /** * 读取卡扣状态 * * @param isLock true:读锁具底座 false:读钥匙底座 * @param type 0:钥匙底座 1:锁具底座1-8 2:锁具底座9、10 */ fun readBuckleStatus(isLock: Boolean, slaveIdx: Int?, doneSingle: ((type: Int, res: ByteArray) -> Unit)? = null) { // TODO 电磁锁控制板可能不是,并且锁和钥匙的读取不一样 slaveIdx?.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, slaveIdx: Int?, lockIdx: Int, done: ((res: ByteArray) -> Unit)? = null) { slaveIdx?.let { modBusManager?.generateLockBuckleCmd(isOpen, lockIdx)?.let { cmd -> modBusManager?.sendTo(it, cmd) { res -> done?.invoke(res) } } } } fun controlLockBuckle(isOpen: Boolean, slaveIdx: Int?, lockIdxList: MutableList, done: ((res: ByteArray) -> Unit)? = null) { slaveIdx?.let { modBusManager?.generateLockBuckleCmd(isOpen, lockIdxList)?.let { cmdList -> cmdList.forEach { cmd -> modBusManager?.sendTo(it, cmd) { res -> done?.invoke(res) } } } } } /** * 读取钥匙RFID */ fun readKeyRfid(slaveIdx: Int?, idx: Int, done: ((isLeft: Boolean, res: ByteArray) -> Unit)? = null) { slaveIdx?.let { modBusManager?.generateRfidCmd(idx)?.let { cmd -> modBusManager?.sendTo(it, cmd) { done?.invoke(idx == 0, it) } } } } /** * 读取锁具RFID */ fun readLockRfid(slaveIdx: Int?, lockIdx: Int, done: ((res: ByteArray) -> Unit)? = null) { slaveIdx?.let { modBusManager?.generateRfidCmd(lockIdx)?.let { cmd -> modBusManager?.sendTo(it, cmd) { res -> done?.invoke(res) } } } } /** * 读便携式底座卡RFID */ fun readPortalCaseCardRfid(slaveIdx: Int?, done: ((res: ByteArray) -> Unit)? = null) { slaveIdx?.let { modBusManager?.generateRfidCmd(8)?.let { cmd -> modBusManager?.sendTo(it, cmd) { res -> done?.invoke(res) } } } } /** * 更新钥匙RFID */ fun updateKeyRfid(slaveIdx: Int, isLeft: Boolean, rfid: String) { dockList.find { it.addr.toInt() == slaveIdx }?.getKeyList()?.find { it.isLeft == isLeft }?.rfid = rfid } /** * 更新钥匙MAC */ fun updateKeyMac(slaveIdx: Int, isLeft: Boolean, mac: String) { dockList.find { it.addr.toInt() == slaveIdx }?.getKeyList()?.find { it.isLeft == isLeft }?.mac = mac } /** * 通过RFID更新对应的Mac */ fun updateKeyMacByRfid(rfid: String, mac: String) { dockList.find { it.type == DOCK_TYPE_KEY }?.getKeyList()?.find { it.rfid == rfid }?.mac = mac } /** * 更新锁具RFID */ fun updateLockRfid(slaveIdx: Int, lockIdx: Int, rfid: String) { dockList.find { it.addr.toInt() == slaveIdx }?.getLockList()?.find { it.idx == lockIdx }?.rfid = rfid } /** * 操作钥匙灯 * * @param leftAction、rightAction 0:保持当前状态 1:点亮 2:熄灭 默认0 */ fun controlKeyLight(slaveIdx: Int?, leftAction: Int = 0, rightAction: Int = 0, done: ((res: ByteArray) -> Unit)? = null) { slaveIdx?.let { modBusManager?.generateKeyLightCmd(leftAction, rightAction)?.let { cmd -> modBusManager?.sendTo(it, cmd) { done?.invoke(it) } } } } /** * 开/关钥匙卡扣 * * @param isOpen true:开操作 false:关操作 * @param isLeft true:左卡扣 false:右卡扣 */ fun controlKeyBuckle(isOpen: Boolean, isLeft: Boolean, slaveIdx: Int?, done: ((res: ByteArray) -> Unit)? = null) { slaveIdx?.let { modBusManager?.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.find { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }?.getKeyList()?.find { it.rfid == rfid } } /** * 根据RFID找锁具 */ fun getLockByRfid(rfid: String): DockBean.LockBean? { return dockList.find { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }?.getLockList()?.find { it.rfid == rfid } } /** * 根据类型获取底座列表 */ 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 openAllLockBuckles() { 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(true, dockBean.addr.toInt() - 1, list) { LogUtil.i("开所有锁卡扣 : ${it.toHexStrings()}") } } } fun closeAllLockBuckles() { 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(false, dockBean.addr.toInt() - 1, list) { LogUtil.i("关所有锁卡扣 : ${it.toHexStrings()}") } } } fun printDockInfo() { println("当前底座列表 : $dockList") dockList.forEach { dockBean -> when (dockBean.type) { DOCK_TYPE_LOCK -> { dockBean.getLockList().forEach { lockBean -> println("${dockBean.addr}锁${lockBean.idx} : ${lockBean.rfid}") } } DOCK_TYPE_KEY -> { dockBean.getKeyList().forEach { keyBean -> println("${dockBean.addr}钥${keyBean.idx} : ${keyBean.rfid}") } } DOCK_TYPE_PORTABLE -> { dockBean.getLockList().forEach { lockBean -> println("${dockBean.addr}柜锁${lockBean.idx} : ${lockBean.rfid}") } dockBean.getKeyList().forEach { keyBean -> println("${dockBean.addr}柜钥${keyBean.idx} : ${keyBean.rfid}") } } } } } fun updateDeviceType() { println("____________________________________") 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") } println("____________________________________") } } /** * 获取一个钥匙(基于钥匙柜和便携柜不存在接一起的情况) * * @return 获取的钥匙RFID,如果数量不足,返回null */ fun getOneKey(): String? { val keyDockList = dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE } val keyList = keyDockList.flatMap { it.getKeyList() }.filter { it.isExist } if (keyList.isEmpty()) { ToastUtils.tip(R.string.key_is_not_enough) return null } return keyList[0].rfid } /** * 根据数量获取锁具(基于锁柜和便携柜不存在接一起的情况) * * @param needLockCount 需要打开的锁具数量 * * @return key: dock地址,value: 锁具RFID列表 */ fun getLocks(needLockCount: Int): MutableMap> { val map = mutableMapOf>() val lockDockList = dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE } var provideCount = 0 lockDockList.forEach loop@ { lockDock -> val lockList = lockDock.getLockList().filter { it.isExist } if (lockList.size < (needLockCount - provideCount)) { provideCount += lockList.size map[lockDock.addr] = lockList.mapNotNull { it.rfid }.toMutableList() } else { val rfidList = lockList.subList(0, needLockCount - provideCount).mapNotNull { it.rfid }.toMutableList() map[lockDock.addr] = rfidList return@loop } } return map } }