| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- 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<DockBean> = 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<StatusListener>()
- // 是否中断读取状态
- private var interruptReadStatus: ArrayList<Boolean> = 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<Int>
- val noLockIdxList = dockBean.getLockList().filter { !it.isExist }.map { it.idx } as MutableList<Int>
- 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<ByteArray>) -> 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<Int>, 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<DockBean> {
- return dockList.filter { it.type == type }
- }
- fun getKeyByDockType(type: Byte): MutableList<DockBean.KeyBean>? {
- 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<Byte, MutableList<String>> {
- val map = mutableMapOf<Byte, MutableList<String>>()
- 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
- }
- }
|