ModBusController.kt 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. package com.grkj.iscs.modbus
  2. import android.content.Context
  3. import com.clj.fastble.BleManager
  4. import com.grkj.iscs.BusinessManager
  5. import com.grkj.iscs.BusinessManager.CAN_RETURN
  6. import com.grkj.iscs.R
  7. import com.grkj.iscs.extentions.removeLeadingZeros
  8. import com.grkj.iscs.extentions.toHexStrings
  9. import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_CARD
  10. import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_FINGERPRINT
  11. import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_KEY
  12. import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_LOCK
  13. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_COLLECT
  14. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_ELEC_LOCK_BOARD
  15. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_KEY
  16. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_LOCK
  17. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_PORTABLE
  18. import com.grkj.iscs.model.vo.hardware.CabinetSlotsRecord
  19. import com.grkj.iscs.util.CommonUtils
  20. import com.grkj.iscs.util.Executor
  21. import com.grkj.iscs.util.NetApi
  22. import com.grkj.iscs.util.ToastUtils
  23. import com.grkj.iscs.util.log.LogUtil
  24. import java.util.concurrent.atomic.AtomicInteger
  25. import java.util.stream.Collectors
  26. /**
  27. * ModBus 主控板控制器
  28. */
  29. object ModBusController {
  30. /**
  31. * 是否初始化完成
  32. */
  33. var isInitReady = false
  34. /**
  35. * 底座列表
  36. */
  37. var dockList: MutableList<DockBean> = mutableListOf()
  38. /**
  39. * 监听状态类型
  40. */
  41. private const val LISTENER_TYPE_STATUS = 3
  42. // 主控板管理器
  43. var modBusManager: ModBusManager? = null
  44. /**
  45. * 监听器
  46. */
  47. private val listeners = ArrayList<StatusListener>()
  48. // 是否中断读取状态
  49. private var interruptReadStatus: ArrayList<Boolean> = ArrayList()
  50. /**
  51. * 重复时间
  52. */
  53. // TODO 临时改成5s
  54. const val REPEAT_FREQUENCY = 800L
  55. /**
  56. * 中断读取
  57. */
  58. fun interruptReadTrashBinStatus(interrupt: Boolean) {
  59. interruptReadStatus.clear()
  60. interruptReadStatus.add(interrupt)
  61. }
  62. /**
  63. * 启动通信引擎
  64. */
  65. @ExperimentalUnsignedTypes
  66. fun start(ctx: Context) {
  67. modBusManager?.stop()
  68. PortManager.openCtrlBord(ctx)?.let { pm ->
  69. return@let ModBusManager(pm, true)
  70. }
  71. // 间隔 1 秒读一遍桶的状态
  72. ?.repeatSendToAll(MBFrame.READ_STATUS, {
  73. interruptReadStatus
  74. }, { res ->
  75. LogUtil.i("****************************************************************************")
  76. // 过滤非空的数据,重置slaveCount
  77. // 不再使用slaveCount,改用地址池
  78. for (l in listeners) {
  79. if (l.type == LISTENER_TYPE_STATUS) {
  80. l.listener(res)
  81. }
  82. }
  83. }, REPEAT_FREQUENCY)?.also {
  84. modBusManager = it
  85. }?.start()
  86. }
  87. /**
  88. * 注册监听器
  89. */
  90. fun registerStatusListener(key: Any, listener: (Any) -> Unit) {
  91. listeners.add(StatusListener(key, listener, LISTENER_TYPE_STATUS))
  92. }
  93. /**
  94. * 取消注册监听器
  95. */
  96. fun unregisterListener(key: Any) {
  97. val it = listeners.iterator()
  98. while (it.hasNext()) {
  99. if (it.next().key == key) {
  100. it.remove()
  101. }
  102. }
  103. }
  104. /**
  105. * 停止引擎
  106. */
  107. fun stop() {
  108. modBusManager?.stop()
  109. }
  110. /**
  111. * 引擎是否运行中
  112. */
  113. fun isRunning(): Boolean? {
  114. return modBusManager?.isRunning()
  115. }
  116. /*****************************************************************************************/
  117. /**
  118. * 初始化所有设备的状态
  119. */
  120. fun initDevicesStatus() {
  121. readDeviceType { res ->
  122. res.forEach { bytes ->
  123. if (bytes.size < 5) return@forEach
  124. // 设备具体数据由0x0011寄存器提供
  125. updateDeviceType(bytes[0], bytes[4])
  126. val type = when (bytes[4]) {
  127. DOCK_TYPE_KEY -> "钥匙底座"
  128. DOCK_TYPE_LOCK -> "锁具底座"
  129. DOCK_TYPE_ELEC_LOCK_BOARD -> "电磁锁控制板"
  130. DOCK_TYPE_PORTABLE -> "便携式底座"
  131. DOCK_TYPE_COLLECT -> "开关量采集板"
  132. else -> "未知"
  133. }
  134. LogUtil.i("initDevicesStatus 设备(${bytes[0].toInt()})类型:$type")
  135. }
  136. // TODO 待完善
  137. Executor.repeatOnMain({
  138. if (isInitReady) {
  139. initLock() // 打开所有无锁的卡扣、关闭所有有锁的卡扣、读取所有锁的RFID
  140. initKey() // 打开所有无钥匙的卡扣、关闭所有有钥匙的卡扣、读取所有钥匙的RFID
  141. return@repeatOnMain false
  142. } else {
  143. return@repeatOnMain true
  144. }
  145. }, REPEAT_FREQUENCY, true)
  146. }
  147. }
  148. /**
  149. * 初始化锁具——打开所有无锁的卡扣、读取RFID
  150. */
  151. private fun initLock() {
  152. LogUtil.i("initLock : $dockList")
  153. dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }
  154. .forEach { dockBean ->
  155. val hasLockIdxList =
  156. dockBean.getLockList().filter { it.isExist }.map { it.idx } as MutableList<Int>
  157. val noLockIdxList =
  158. dockBean.getLockList().filter { !it.isExist }.map { it.idx } as MutableList<Int>
  159. hasLockIdxList.forEach { idx ->
  160. readLockRfid(dockBean.addr, idx) { res ->
  161. if (res.size < 11) {
  162. LogUtil.e("Lock rfid error")
  163. return@readLockRfid
  164. }
  165. val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  166. LogUtil.i("初始化锁具 RFID : $rfid")
  167. updateLockRfid(dockBean.addr, idx, rfid)
  168. NetApi.getLockInfo(rfid) {
  169. updateLockNewHardware(dockBean.addr, idx, it == null)
  170. }
  171. }
  172. }
  173. controlLockBuckle(false, dockBean.addr, hasLockIdxList)
  174. controlLockBuckle(true, dockBean.addr, noLockIdxList)
  175. }
  176. }
  177. /**
  178. * 初始化钥匙
  179. */
  180. private fun initKey() {
  181. LogUtil.i("initKey : $dockList")
  182. dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }
  183. .forEach { dockBean ->
  184. dockBean.getKeyList().forEach { key ->
  185. if (key.isExist) {
  186. LogUtil.i("initKey : ${dockBean.addr} : ${key.isLeft}")
  187. readKeyRfid(dockBean.addr, if (key.isLeft) 0 else 1) { isLeft, res ->
  188. if (res.size < 11) {
  189. LogUtil.e("Key rfid error")
  190. return@readKeyRfid
  191. }
  192. val rfid =
  193. res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  194. LogUtil.i("初始化钥匙 RFID : $rfid")
  195. // 更新rfid
  196. updateKeyRfid(dockBean.addr, isLeft, rfid)
  197. // 蓝牙准备操作
  198. NetApi.getKeyInfo(rfid) {
  199. LogUtil.i("getKeyInfo : $rfid - ${it?.macAddress}")
  200. updateKeyNewHardware(dockBean.addr, isLeft, it == null)
  201. if (it != null && !it.macAddress.isNullOrEmpty()) {
  202. // 更新mac
  203. updateKeyMac(dockBean.addr, key.isLeft, it.macAddress)
  204. BusinessManager.registerConnectListener(
  205. it.macAddress,
  206. false
  207. ) { isDone, bleBean ->
  208. if (isDone && bleBean?.bleDevice != null) {
  209. Executor.delayOnMain(500) {
  210. BusinessManager.getCurrentStatus(
  211. 3, bleBean.bleDevice
  212. )
  213. }
  214. }
  215. }
  216. } else {
  217. ToastUtils.tip(R.string.get_key_info_fail)
  218. }
  219. }
  220. }
  221. controlKeyBuckle(false, key.isLeft, dockBean.addr)
  222. } else {
  223. controlKeyBuckle(true, key.isLeft, dockBean.addr)
  224. }
  225. }
  226. }
  227. }
  228. /**
  229. * 获取最新状态
  230. */
  231. fun updateStatus(byteArray: ByteArray): DockBean? {
  232. if (byteArray.isEmpty()) {
  233. return null
  234. }
  235. val dockB = dockList.find { it.addr == byteArray[0] }
  236. return dockB?.parseStatus(byteArray)
  237. }
  238. /**
  239. * 更新所有锁仓状态
  240. */
  241. fun updateAllBuckleStatus(done: () -> Unit) {
  242. val remaining = AtomicInteger(2)
  243. modBusManager?.sendToAll(MBFrame.READ_BUCKLE_STATUS) { res ->
  244. LogUtil.i("****************************************************************************")
  245. // 过滤非空的数据,重置slaveCount
  246. // 不再使用slaveCount,改用地址池
  247. lockBuckleStatus(res)
  248. // 每完成一个就把计数减一,减到 0 就触发 done()
  249. if (remaining.decrementAndGet() == 0) {
  250. done()
  251. }
  252. }
  253. modBusManager?.sendToAll(MBFrame.READ_LOCK_BUCKLE_EXTRA_STATUS) { res ->
  254. LogUtil.i("****************************************************************************")
  255. // 过滤非空的数据,重置slaveCount
  256. // 不再使用slaveCount,改用地址池
  257. lockBuckleExtraStatus(res)
  258. // 每完成一个就把计数减一,减到 0 就触发 done()
  259. if (remaining.decrementAndGet() == 0) {
  260. done()
  261. }
  262. }
  263. }
  264. /**
  265. * 更新开关状态
  266. */
  267. fun updateSwitchStatus(done: () -> Unit) {
  268. modBusManager?.mSlaveAddressList?.find { it == (0xA1).toByte() }?.let {
  269. modBusManager?.sendTo(it, MBFrame.READ_BUCKLE_STATUS) { res ->
  270. LogUtil.i("****************************************************************************")
  271. // 过滤非空的数据,重置slaveCount
  272. // 不再使用slaveCount,改用地址池
  273. switchStatus(res, done)
  274. }
  275. }
  276. }
  277. /**
  278. * 第9,10锁位卡扣状态
  279. */
  280. private fun lockBuckleExtraStatus(res: Any) {
  281. LogUtil.i("硬件状态:${(res as List<ByteArray>).map { it.toHexStrings() }}")
  282. if (res.isEmpty() || res.any { it.isEmpty() }) {
  283. var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : "
  284. val addressList = mutableListOf<String>()
  285. modBusManager?.mSlaveAddressList?.forEach { itDock ->
  286. if (res.none { it.isNotEmpty() && it[0] == itDock }) {
  287. addressList.add("0x${String.format("%02X", itDock)}")
  288. }
  289. }
  290. tipStr += addressList
  291. ToastUtils.tip(tipStr)
  292. }
  293. res.forEach { bytes ->
  294. val dockBean = updateExtraLockStatus(bytes) ?: return@forEach
  295. if (!CAN_RETURN) {
  296. return@forEach
  297. }
  298. when (dockBean.type) {
  299. DOCK_TYPE_LOCK -> {
  300. dockBean.getLockList().filter { it.idx > 7 }.forEach { lockBean ->
  301. updateLockStatus(
  302. dockBean.addr, lockBean.idx, lockBean.lockEnabled
  303. )
  304. }
  305. }
  306. }
  307. }
  308. }
  309. /**
  310. * 开关量更新
  311. */
  312. private fun switchStatus(res: Any, done: () -> Unit) {
  313. LogUtil.i("开关板:${(res as ByteArray).toHexStrings()}")
  314. if (res.isEmpty()) {
  315. var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : "
  316. val addressList = mutableListOf<String>()
  317. modBusManager?.mSlaveAddressList?.forEach { itDock ->
  318. if (res.isNotEmpty() && res == itDock) {
  319. addressList.add("0x${String.format("%02X", itDock)}")
  320. }
  321. }
  322. tipStr += addressList
  323. ToastUtils.tip(tipStr)
  324. }
  325. updateSwitchStatus(res, done)
  326. }
  327. /**
  328. * 第1-8锁位卡扣状态和钥匙
  329. */
  330. private fun lockBuckleStatus(res: Any) {
  331. LogUtil.i("硬件状态:${(res as List<ByteArray>).map { it.toHexStrings() }}")
  332. if (res.isEmpty() || res.any { it.isEmpty() }) {
  333. var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : "
  334. val addressList = mutableListOf<String>()
  335. modBusManager?.mSlaveAddressList?.forEach { itDock ->
  336. if (res.none { it.isNotEmpty() && it[0] == itDock }) {
  337. addressList.add("0x${String.format("%02X", itDock)}")
  338. }
  339. }
  340. tipStr += addressList
  341. ToastUtils.tip(tipStr)
  342. }
  343. res.forEach { bytes ->
  344. val dockBean = updateLockStatus(bytes) ?: return@forEach
  345. if (!CAN_RETURN) {
  346. return@forEach
  347. }
  348. when (dockBean.type) {
  349. DOCK_TYPE_KEY -> {
  350. dockBean.getKeyList().forEach { keyBean ->
  351. updateKeyLockStatus(
  352. dockBean.addr, keyBean.isLeft, keyBean.lockEnabled
  353. )
  354. //todo 更新锁仓状态
  355. }
  356. }
  357. DOCK_TYPE_LOCK -> {
  358. dockBean.getLockList().forEach { lockBean ->
  359. updateLockStatus(
  360. dockBean.addr, lockBean.idx, lockBean.lockEnabled
  361. )
  362. }
  363. }
  364. DOCK_TYPE_ELEC_LOCK_BOARD -> {
  365. // TODO 占位
  366. }
  367. DOCK_TYPE_PORTABLE -> {
  368. // TODO 便携式待完善
  369. dockBean.deviceList.forEach { deviceBean ->
  370. if (deviceBean.isExist) {
  371. when (deviceBean.type) {
  372. DEVICE_TYPE_KEY -> {
  373. updateKeyLockStatus(
  374. dockBean.addr, true, deviceBean.lockEnabled
  375. )
  376. }
  377. DEVICE_TYPE_LOCK -> {
  378. updateLockStatus(
  379. dockBean.addr, deviceBean.idx, deviceBean.lockEnabled
  380. )
  381. }
  382. DEVICE_TYPE_CARD -> {
  383. readPortalCaseCardRfid(dockBean.addr) { res ->
  384. if (res.size < 11) {
  385. LogUtil.e("Portal Case card rfid error")
  386. return@readPortalCaseCardRfid
  387. }
  388. val rfid = res.copyOfRange(3, 11).toHexStrings(false)
  389. .removeLeadingZeros()
  390. LogUtil.i("卡片RFID : $rfid")
  391. }
  392. }
  393. DEVICE_TYPE_FINGERPRINT -> {
  394. }
  395. }
  396. }
  397. }
  398. }
  399. }
  400. }
  401. }
  402. /**
  403. * 获取第1-8的锁仓数据和左右钥匙数据
  404. */
  405. private fun updateLockStatus(byteArray: ByteArray): DockBean? {
  406. if (byteArray.isEmpty()) {
  407. return null
  408. }
  409. val dockB = dockList.find { it.addr == byteArray[0] }
  410. return dockB?.parseLockStatus(byteArray)
  411. }
  412. /**
  413. * 更新开关状态
  414. */
  415. private fun updateSwitchStatus(byteArray: ByteArray, done: () -> Unit): DockBean? {
  416. if (byteArray.isEmpty()) {
  417. return null
  418. }
  419. val dockB = dockList.find { it.addr == byteArray[0] }
  420. return dockB?.parseSwitchStatus(byteArray, done)
  421. }
  422. /**
  423. * 获取额外的9,10锁仓数据
  424. */
  425. private fun updateExtraLockStatus(byteArray: ByteArray): DockBean? {
  426. if (byteArray.isEmpty()) {
  427. return null
  428. }
  429. val dockB = dockList.find { it.addr == byteArray[0] && it.type == DOCK_TYPE_LOCK }
  430. return dockB?.parseExtraLockStatus(byteArray)
  431. }
  432. /**
  433. * 读取设备类型
  434. */
  435. private fun readDeviceType(done: ((res: List<ByteArray>) -> Unit)? = null) {
  436. modBusManager?.sendToAll(MBFrame.READ_DEVICE_TYPE) { res ->
  437. done?.invoke(res)
  438. }
  439. }
  440. /**
  441. * 更新设备类型
  442. */
  443. private fun updateDeviceType(idx: Byte, type: Byte?) {
  444. val dock = dockList.find { it.addr == idx }
  445. dock?.let {
  446. it.type = type
  447. } ?: let {
  448. dockList.add(DockBean(idx, type, true, mutableListOf()))
  449. }
  450. }
  451. /**
  452. * 读取卡扣状态
  453. *
  454. * @param isLock true:读锁具底座 false:读钥匙底座
  455. * @param type 0:钥匙底座 1:锁具底座1-8 2:锁具底座9、10
  456. */
  457. fun readBuckleStatus(
  458. isLock: Boolean,
  459. slaveAddress: Byte?,
  460. doneSingle: ((type: Int, res: ByteArray) -> Unit)? = null
  461. ) {
  462. // TODO 电磁锁控制板可能不是,并且锁和钥匙的读取不一样
  463. slaveAddress?.let {
  464. modBusManager?.sendTo(it, MBFrame.READ_BUCKLE_STATUS) { res ->
  465. doneSingle?.invoke(if (isLock) 1 else 0, res)
  466. }
  467. if (isLock) {
  468. modBusManager?.sendTo(it, MBFrame.READ_LOCK_BUCKLE_EXTRA_STATUS) { res ->
  469. doneSingle?.invoke(2, res)
  470. }
  471. }
  472. }
  473. }
  474. /**
  475. * 开/关锁具卡扣 单
  476. */
  477. fun controlLockBuckle(
  478. isOpen: Boolean, slaveAddress: Byte?, lockIdx: Int, done: ((res: ByteArray) -> Unit)? = null
  479. ) {
  480. slaveAddress?.let {
  481. ModBusCMDHelper.generateLockBuckleCmd(isOpen, lockIdx)?.let { cmd ->
  482. modBusManager?.sendTo(it, cmd) { res ->
  483. done?.invoke(res)
  484. }
  485. }
  486. }
  487. }
  488. /**
  489. * 开/关锁具卡扣 多
  490. */
  491. fun controlLockBuckle(
  492. isOpen: Boolean,
  493. slaveAddress: Byte?,
  494. lockIdxList: MutableList<Int>,
  495. done: ((res: ByteArray) -> Unit)? = null
  496. ) {
  497. slaveAddress?.let {
  498. ModBusCMDHelper.generateLockBuckleCmd(isOpen, lockIdxList)?.let { cmdList ->
  499. cmdList.forEach { cmd ->
  500. modBusManager?.sendTo(it, cmd) { res ->
  501. done?.invoke(res)
  502. }
  503. }
  504. }
  505. }
  506. }
  507. /**
  508. * 读取钥匙RFID
  509. */
  510. fun readKeyRfid(
  511. slaveAddress: Byte?, idx: Int, done: ((isLeft: Boolean, res: ByteArray) -> Unit)? = null
  512. ) {
  513. slaveAddress?.let {
  514. ModBusCMDHelper.generateRfidCmd(idx)?.let { cmd ->
  515. modBusManager?.sendTo(it, cmd) {
  516. done?.invoke(idx == 0, it)
  517. }
  518. }
  519. }
  520. }
  521. /**
  522. * 读取锁具RFID
  523. */
  524. fun readLockRfid(slaveAddress: Byte?, lockIdx: Int, done: ((res: ByteArray) -> Unit)? = null) {
  525. slaveAddress?.let {
  526. ModBusCMDHelper.generateRfidCmd(lockIdx)?.let { cmd ->
  527. modBusManager?.sendTo(it, cmd) { res ->
  528. done?.invoke(res)
  529. }
  530. }
  531. }
  532. }
  533. /**
  534. * 读便携式底座卡RFID
  535. */
  536. fun readPortalCaseCardRfid(slaveAddress: Byte?, done: ((res: ByteArray) -> Unit)? = null) {
  537. slaveAddress?.let {
  538. ModBusCMDHelper.generateRfidCmd(8)?.let { cmd ->
  539. modBusManager?.sendTo(it, cmd) { res ->
  540. done?.invoke(res)
  541. }
  542. }
  543. }
  544. }
  545. /**
  546. * 更新钥匙RFID
  547. */
  548. fun updateKeyRfid(slaveAddress: Byte, isLeft: Boolean, rfid: String) {
  549. dockList.find { it.addr == slaveAddress }?.getKeyList()
  550. ?.find { it.isLeft == isLeft }?.rfid = rfid
  551. }
  552. /**
  553. * 更新钥匙锁仓状态
  554. */
  555. private fun updateKeyLockStatus(slaveAddress: Byte, isLeft: Boolean, lockEnabled: Boolean) {
  556. dockList.find { it.addr == slaveAddress }?.getKeyList()
  557. ?.find { it.isLeft == isLeft }?.lockEnabled = lockEnabled
  558. }
  559. /**
  560. * 更新钥匙MAC
  561. */
  562. fun updateKeyMac(slaveAddress: Byte, isLeft: Boolean, mac: String) {
  563. dockList.find { it.addr == slaveAddress }?.getKeyList()?.find { it.isLeft == isLeft }?.mac =
  564. mac
  565. }
  566. /**
  567. * 更新钥匙时候为新设备
  568. */
  569. fun updateKeyNewHardware(slaveAddress: Byte, isLeft: Boolean, newHardware: Boolean) {
  570. dockList.find { it.addr == slaveAddress }?.getKeyList()
  571. ?.find { it.isLeft == isLeft }?.newHardware = newHardware
  572. }
  573. /**
  574. * 更新锁具RFID
  575. */
  576. fun updateLockRfid(slaveAddress: Byte, lockIdx: Int, rfid: String) {
  577. dockList.find { it.addr == slaveAddress }?.getLockList()?.find { it.idx == lockIdx }?.rfid =
  578. rfid
  579. }
  580. /**
  581. * 更新锁是不是新设备,就是后台没有数据的
  582. */
  583. fun updateLockNewHardware(slaveAddress: Byte, lockIdx: Int, newHardware: Boolean) {
  584. dockList.find { it.addr == slaveAddress }?.getLockList()
  585. ?.find { it.idx == lockIdx }?.newHardware = newHardware
  586. }
  587. /**
  588. * 更新锁仓状态
  589. */
  590. fun updateLockStatus(slaveAddress: Byte, lockIdx: Int, lockEnabled: Boolean) {
  591. dockList.find { it.addr == slaveAddress }?.getLockList()
  592. ?.find { it.idx == lockIdx }?.lockEnabled = lockEnabled
  593. }
  594. /**
  595. * 控制钥匙卡扣
  596. */
  597. fun controlKeyBuckle(isOpen: Boolean, mac: String, done: ((res: ByteArray) -> Unit)? = null) {
  598. val dockBean = getDockByKeyMac(mac)
  599. dockBean ?: return
  600. val key = getKeyByMac(mac)
  601. key ?: return
  602. controlKeyBuckle(isOpen, key.isLeft, dockBean.addr, done)
  603. }
  604. /**
  605. * 开/关钥匙卡扣
  606. *
  607. * @param isOpen true:开操作 false:关操作
  608. * @param isLeft true:左卡扣 false:右卡扣
  609. */
  610. fun controlKeyBuckle(
  611. isOpen: Boolean,
  612. isLeft: Boolean,
  613. slaveAddress: Byte?,
  614. done: ((res: ByteArray) -> Unit)? = null
  615. ) {
  616. slaveAddress?.let {
  617. ModBusCMDHelper.generateKeyBuckleCmd(isOpen, if (isLeft) 0 else 1)?.let { cmd ->
  618. modBusManager?.sendTo(it, cmd) { res ->
  619. done?.invoke(res)
  620. }
  621. }
  622. }
  623. }
  624. /**
  625. * 根据RFID找钥匙
  626. */
  627. fun getKeyByRfid(rfid: String): DockBean.KeyBean? {
  628. return dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }
  629. .flatMap { it.getKeyList() }.find { it.rfid == rfid }
  630. }
  631. /**
  632. * 根据Mac找钥匙
  633. */
  634. fun getKeyByMac(mac: String): DockBean.KeyBean? {
  635. return dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }
  636. .flatMap { it.getKeyList() }.find { it.mac == mac }
  637. }
  638. /**
  639. * 根据底座获取钥匙
  640. */
  641. fun getKeyByDock(dockAddr: Byte?, isLeft: Boolean): DockBean.KeyBean? {
  642. dockAddr ?: return null
  643. return dockList.find { it.addr == dockAddr }?.getKeyList()?.find { it.isLeft == isLeft }
  644. }
  645. /**
  646. * 钥匙是否存在
  647. */
  648. fun isKeyExist(dockAddr: Byte?, isLeft: Boolean): Boolean {
  649. dockAddr ?: return false
  650. return dockList.find { it.addr == dockAddr }?.getKeyList()
  651. ?.find { it.isLeft == isLeft && it.isExist } != null
  652. }
  653. /**
  654. * 获取钥匙锁仓的锁定状态
  655. */
  656. fun getKeyBuckleLockEnabled(dockAddr: Byte?, isLeft: Boolean): Boolean {
  657. dockAddr ?: return false
  658. return dockList.find { it.addr == dockAddr }?.getKeyList()
  659. ?.find { it.isLeft == isLeft }?.lockEnabled == true
  660. }
  661. /**
  662. * 获取挂锁锁仓的锁定状态
  663. */
  664. fun getLockBuckleLockEnabled(dockAddr: Byte?, lockIdx: Int): Boolean {
  665. dockAddr ?: return false
  666. return dockList.find { it.addr == dockAddr }?.getLockList()
  667. ?.find { it.idx == lockIdx }?.lockEnabled == true
  668. }
  669. /**
  670. * 获取挂锁是否存在
  671. */
  672. fun isLockExist(dockAddr: Byte?, lockIdx: Int): Boolean {
  673. dockAddr ?: return false
  674. return dockList.find { it.addr == dockAddr }?.getLockList()
  675. ?.find { it.idx == lockIdx && it.isExist } != null
  676. }
  677. /**
  678. * 获取钥匙状态
  679. *
  680. * @return 0:不存在 1:存在 2:有RFID 3:有MAC 4:连接上 5:待机模式 6: 待机模式无异常
  681. */
  682. fun getKeyStatus(dockAddr: Byte?, isLeft: Boolean): Int {
  683. dockAddr ?: return 0
  684. val key = dockList.find { it.addr == dockAddr }?.getKeyList()?.find { it.isLeft == isLeft }
  685. LogUtil.i("getKeyStatus key : $key")
  686. key ?: return 0
  687. var status = 0
  688. if (key.isExist) {
  689. status = 1
  690. } else {
  691. return status
  692. }
  693. if (key.rfid != null) {
  694. status = 2
  695. } else {
  696. return status
  697. }
  698. if (key.mac != null) {
  699. status = 3
  700. } else {
  701. return status
  702. }
  703. if (BleManager.getInstance()
  704. .isConnected(BusinessManager.getBleDeviceByMac(key.mac)?.bleDevice)
  705. ) {
  706. status = 4
  707. } else {
  708. return status
  709. }
  710. if (key.isReady) {
  711. status = 5
  712. } else {
  713. return status
  714. }
  715. if (key.rfid != null && BusinessManager.mExceptionKeyList.none { it == key.rfid }) {
  716. status = 6
  717. } else {
  718. return status
  719. }
  720. return status
  721. }
  722. /**
  723. * 更新钥匙的准备状态
  724. */
  725. fun updateKeyReadyStatus(mac: String, isReady: Boolean, from: Int) {
  726. LogUtil.i("updateKeyReadyStatus mac : $mac - $isReady - $from")
  727. dockList.forEach {
  728. if (it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE) {
  729. if (it.getKeyList().any { it.mac == mac }) {
  730. it.getKeyList().find { it.mac == mac }?.isReady = isReady
  731. }
  732. }
  733. }
  734. }
  735. /**
  736. * 根据钥匙Mac获取底座
  737. */
  738. fun getDockByKeyMac(mac: String): DockBean? {
  739. return dockList.find {
  740. (it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE) && it.getKeyList()
  741. .any { it.mac == mac }
  742. }
  743. }
  744. /**
  745. * 根据类型获取底座列表
  746. */
  747. fun getDockByType(type: Byte): List<DockBean> {
  748. return dockList.filter { it.type == type }
  749. }
  750. /**
  751. * 根据底座类型获取钥匙列表
  752. */
  753. fun getKeyByDockType(type: Byte): MutableList<DockBean.KeyBean>? {
  754. return dockList.find { it.type == type }?.let {
  755. it.getKeyList()
  756. }
  757. }
  758. /**
  759. * 全部锁扣的开关
  760. */
  761. fun controlAllLockBuckles(isOpen: Boolean) {
  762. dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }
  763. .forEach { dockBean ->
  764. val list =
  765. dockBean.getLockList().stream().map { it.idx }.collect(Collectors.toList())
  766. controlLockBuckle(isOpen, dockBean.addr, list) {
  767. LogUtil.i("${if (isOpen) "开启" else "关闭"}所有锁卡扣 : ${it.toHexStrings()}")
  768. }
  769. }
  770. }
  771. /**
  772. * 打印全部底座信息
  773. */
  774. fun printDockInfo() {
  775. LogUtil.i("当前底座列表 : $dockList")
  776. dockList.forEach { dockBean ->
  777. when (dockBean.type) {
  778. DOCK_TYPE_LOCK -> {
  779. dockBean.getLockList().forEach { lockBean ->
  780. LogUtil.i("${dockBean.addr}锁${lockBean.idx} : ${lockBean.rfid}")
  781. }
  782. }
  783. DOCK_TYPE_KEY -> {
  784. dockBean.getKeyList().forEach { keyBean ->
  785. LogUtil.i("${dockBean.addr}钥${keyBean.idx} : ${keyBean.rfid}")
  786. }
  787. }
  788. DOCK_TYPE_PORTABLE -> {
  789. dockBean.getLockList().forEach { lockBean ->
  790. LogUtil.i("${dockBean.addr}柜锁${lockBean.idx} : ${lockBean.rfid}")
  791. }
  792. dockBean.getKeyList().forEach { keyBean ->
  793. LogUtil.i("${dockBean.addr}柜钥${keyBean.idx} : ${keyBean.rfid}")
  794. }
  795. }
  796. }
  797. }
  798. }
  799. /**
  800. * 更新设备类型
  801. */
  802. fun updateDeviceType() {
  803. LogUtil.i("____________________________________")
  804. readDeviceType { res ->
  805. LogUtil.i("设备类型数量 : ${res.size}")
  806. LogUtil.i("设备类型 : ${res.map { it.toHexStrings() }}")
  807. res.forEach { bytes ->
  808. if (bytes.size < 5) return@forEach
  809. // 设备具体数据由0x0011寄存器提供
  810. updateDeviceType(bytes[0], bytes[4])
  811. val type = when (bytes[4]) {
  812. DOCK_TYPE_KEY -> "钥匙底座"
  813. DOCK_TYPE_LOCK -> "锁具底座"
  814. DOCK_TYPE_ELEC_LOCK_BOARD -> "电磁锁控制板"
  815. DOCK_TYPE_PORTABLE -> "便携式底座"
  816. else -> "未知"
  817. }
  818. LogUtil.i("设备(${bytes[0].toInt()})类型:$type")
  819. }
  820. LogUtil.i("____________________________________")
  821. }
  822. }
  823. /**
  824. * 随机获取一个钥匙(存在的、有RFID、有Mac、连接的、是待机模式的)
  825. *
  826. * @return 底座地址,钥匙
  827. */
  828. fun getOneKey(
  829. exceptionSlots: MutableList<CabinetSlotsRecord>,
  830. exceptionKeys: MutableList<String>
  831. ): Pair<Byte, DockBean.KeyBean?>? {
  832. val keyDockList =
  833. dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }
  834. keyDockList.sortedBy { it.addr }
  835. keyDockList.forEach { it.deviceList.sortedBy { it.idx } }
  836. val keyList =
  837. keyDockList.map { it.deviceList }.flatten()
  838. .filterIsInstance<DockBean.KeyBean>()
  839. .filterIndexed { index, _ -> (index + 1) !in exceptionSlots.map { it.col?.toInt() } }
  840. .filter { it.rfid !in exceptionKeys && !it.rfid.isNullOrEmpty() && !it.mac.isNullOrEmpty() && it.isExist }
  841. .toMutableList()
  842. LogUtil.i("keyList : $keyList")
  843. if (keyList.isEmpty()) {
  844. ToastUtils.tip(R.string.no_available_key)
  845. return null
  846. }
  847. keyList.forEach {
  848. LogUtil.i(
  849. "keyStatus 满足条件的钥匙: ${it.isExist} - ${it.rfid} - ${it.mac} - ${it.isReady} - " + "${
  850. BusinessManager.getBleDeviceByMac(
  851. it.mac
  852. )?.bleDevice != null
  853. } - " + "${
  854. BleManager.getInstance()
  855. .isConnected(BusinessManager.getBleDeviceByMac(it.mac)?.bleDevice)
  856. } - " + "${!BusinessManager.mExceptionKeyList.contains(it.rfid)}"
  857. )
  858. }
  859. val key = keyList.filter {
  860. it.isExist && it.rfid != null && it.mac != null && it.isReady && BleManager.getInstance()
  861. .isConnected(BusinessManager.getBleDeviceByMac(it.mac)?.bleDevice) && !BusinessManager.mExceptionKeyList.contains(
  862. it.rfid
  863. )
  864. }.shuffled().firstOrNull()
  865. if (key == null) {
  866. LogUtil.e("getOneKey : no key match")
  867. return null
  868. }
  869. val address = keyDockList.find { it.getKeyList().any { it.rfid == key.rfid } }?.addr
  870. if (address == null) {
  871. LogUtil.e("getOneKey : no dock match")
  872. return null
  873. }
  874. return Pair(address, key)
  875. }
  876. /**
  877. * 根据数量获取锁具(基于锁柜和便携柜不存在接一起的情况)
  878. *
  879. * @param needLockCount 需要打开的锁具数量
  880. *
  881. * @return key: dock地址,value: 锁具RFID列表
  882. */
  883. fun getLocks(
  884. needLockCount: Int,
  885. exceptionSlots: MutableList<CabinetSlotsRecord>,
  886. exceptionLocks: MutableList<String>
  887. ): MutableMap<Byte, MutableList<DockBean.LockBean>> {
  888. val map = mutableMapOf<Byte, MutableList<DockBean.LockBean>>()
  889. if (needLockCount == 0) {
  890. return map
  891. }
  892. val lockDockList =
  893. dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }
  894. lockDockList.sortedBy { it.addr }
  895. var provideCount = 0
  896. for (lockDockIndex in lockDockList.indices) {
  897. if (provideCount >= needLockCount) break
  898. val validLocks =
  899. lockDockList[lockDockIndex].getLockList().filter { it.rfid !in exceptionLocks }
  900. .filter {
  901. it.isExist && it.idx !in exceptionSlots.filter { it.row?.toInt() == (lockDockIndex + 1) }
  902. .map { (it.col?.toInt() ?: 1) - 1 }
  903. }
  904. val toTake = (needLockCount - provideCount).coerceAtMost(validLocks.size)
  905. if (toTake > 0) {
  906. map[lockDockList[lockDockIndex].addr] = validLocks.take(toTake).toMutableList()
  907. provideCount += toTake
  908. }
  909. }
  910. return map
  911. }
  912. /**
  913. * 获取开关量数据
  914. */
  915. fun getSwitchData(): MutableList<DockBean.SwitchBean> {
  916. return dockList.filter { it.type == DOCK_TYPE_COLLECT }.sortedBy { it.addr }
  917. .flatMap { it.getSwitchList() }.mapIndexed { index, switchBean ->
  918. DockBean.SwitchBean(index, switchBean.switchBoardAddr, switchBean.enabled)
  919. }.toMutableList()
  920. }
  921. /**
  922. * 读取开关采集板数据
  923. */
  924. fun readSwitchStatus(
  925. slaveAddress: Byte?, addr: ByteArray, done: ((res: ByteArray) -> Unit)? = null
  926. ) {
  927. slaveAddress?.let {
  928. ModBusCMDHelper.generateSwitchBoardStatusCmd(addr)?.let { cmd ->
  929. modBusManager?.sendTo(it, cmd) { res ->
  930. done?.invoke(res)
  931. }
  932. }
  933. }
  934. }
  935. }