ModBusController.kt 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. package com.grkj.iscs.modbus
  2. import android.content.Context
  3. import com.grkj.iscs.extentions.removeLeadingZeros
  4. import com.grkj.iscs.extentions.toHexStrings
  5. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_ELEC_LOCK_BOARD
  6. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_KEY
  7. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_LOCK
  8. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_PORTABLE
  9. import com.grkj.iscs.util.Executor
  10. import com.grkj.iscs.util.log.LogUtil
  11. import java.util.concurrent.Executors
  12. import java.util.stream.Collectors
  13. /**
  14. * ModBus 主控板控制器
  15. */
  16. object ModBusController {
  17. /**
  18. * 底座列表
  19. */
  20. var dockList: MutableList<DockBean> = mutableListOf()
  21. private const val LISTENER_TYPE_STATUS = 3
  22. // 主控板管理器
  23. private var modBusManager: ModBusManager? = null
  24. private var slaveCount: Int = 0
  25. private val threadPool = Executors.newScheduledThreadPool(4)
  26. private val listeners = ArrayList<StatusListener>()
  27. // 是否中断读取状态
  28. private var interruptReadStatus: ArrayList<Boolean> = ArrayList()
  29. var shouldStopUpgrade = false
  30. fun setSlaveCount(count: Int) {
  31. modBusManager?.slaveCount = count
  32. slaveCount = count
  33. }
  34. class StatusListener(
  35. val key: Any,
  36. val listener: (Any) -> Unit,
  37. val type: Int
  38. )
  39. fun interruptReadTrashBinStatus(interrupt: Boolean) {
  40. interruptReadStatus.clear()
  41. interruptReadStatus.add(interrupt)
  42. }
  43. @ExperimentalUnsignedTypes
  44. fun start(ctx: Context) {
  45. modBusManager?.stop()
  46. PortManager.openCtrlBord(ctx)
  47. ?.let { pm ->
  48. return@let ModBusManager(slaveCount, pm, true)
  49. }
  50. // 间隔 1 秒读一遍桶的状态
  51. ?.repeatSendToAll(MBFrame.READ_STATUS, {
  52. interruptReadStatus
  53. }, { res ->
  54. // // Logger.d("ModbusController", "res: ${res.map { it.toHexString() }}")
  55. LogUtil.i("****************************************************************************")
  56. for (l in listeners) {
  57. if (l.type == LISTENER_TYPE_STATUS) {
  58. l.listener(res)
  59. }
  60. }
  61. // TODO 临时改成5s
  62. // }, 1000)
  63. }, 5000)
  64. ?.also {
  65. modBusManager = it
  66. Executor.runOnIO {
  67. // refreshAllowOpenDoorUnidentified(ctx, it)
  68. }
  69. }
  70. ?.start()
  71. }
  72. fun registerStatusListener(key: Any, listener: (Any) -> Unit) {
  73. listeners.add(StatusListener(key, listener, LISTENER_TYPE_STATUS))
  74. }
  75. fun unregisterListener(key: Any) {
  76. val it = listeners.iterator()
  77. while (it.hasNext()) {
  78. if (it.next().key == key) {
  79. it.remove()
  80. }
  81. }
  82. }
  83. fun stop() {
  84. modBusManager?.stop()
  85. }
  86. /*****************************************************************************************/
  87. /**
  88. * 初始化所有设备的状态
  89. */
  90. // TODO 通电后多久执行?App每次重启的执行是什么
  91. fun initDevicesStatus() {
  92. readDeviceType { res ->
  93. res.forEach { bytes ->
  94. if (bytes.size < 5) return@forEach
  95. // TODO 设备具体数据由0x0011寄存器提供
  96. updateDeviceType(bytes[0], bytes[4])
  97. val type = when (bytes[4]) {
  98. DOCK_TYPE_KEY -> "钥匙底座"
  99. DOCK_TYPE_LOCK -> "锁具底座"
  100. DOCK_TYPE_ELEC_LOCK_BOARD -> "电磁锁控制板"
  101. DOCK_TYPE_PORTABLE -> "便携式底座"
  102. else -> "未知"
  103. }
  104. LogUtil.i("initDevicesStatus 设备(${bytes[0].toInt()})类型:$type")
  105. }
  106. }
  107. Executor.delayOnMain({
  108. // TODO 待完善
  109. initLock() // TODO 打开所有无锁的卡扣、读取所有锁的RFID
  110. initKey() // TODO 打开所有无钥匙的卡扣、关闭所有钥匙灯光、读取所有钥匙的RFID
  111. // TODO 设置所有钥匙的模式
  112. // TODO 通过HTTP获取所有钥匙的Mac
  113. }, 3000)
  114. }
  115. /**
  116. * 初始化锁具——打开所有无锁的卡扣、读取RFID
  117. */
  118. private fun initLock() {
  119. LogUtil.i("initLock : $dockList")
  120. dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }.forEach { dockBean ->
  121. val hasLockIdxList = dockBean.getLockList().filter { it.isExist }.map { it.idx } as MutableList<Int>
  122. val noLockIdxList = dockBean.getLockList().filter { !it.isExist }.map { it.idx } as MutableList<Int>
  123. hasLockIdxList.forEach { idx ->
  124. readLockRfid(dockBean.addr.toInt() - 1, idx) { res ->
  125. val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  126. LogUtil.i("初始化锁具 RFID : $rfid")
  127. updateLockRfid(dockBean.addr.toInt(), idx, rfid)
  128. }
  129. }
  130. controlLockBuckle(false, dockBean.addr.toInt() - 1, hasLockIdxList)
  131. controlLockBuckle(true, dockBean.addr.toInt() - 1, noLockIdxList)
  132. }
  133. }
  134. /**
  135. * 初始化钥匙——关闭所有钥匙灯光
  136. */
  137. private fun initKey() {
  138. LogUtil.i("initKey : $dockList")
  139. dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }.forEach { dockBean ->
  140. controlKeyLight(dockBean.addr.toInt() - 1, 2, 2)
  141. dockBean.getKeyList().forEach { key ->
  142. if (key.isExist) {
  143. LogUtil.i("initKey : ${dockBean.addr.toInt() - 1} : ${key.isLeft}")
  144. readKeyRfid(dockBean.addr.toInt() - 1, if (key.isLeft) 0 else 1) { isLeft, res ->
  145. val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  146. LogUtil.i("初始化钥匙 RFID : $rfid")
  147. updateKeyRfid(dockBean.addr.toInt(), isLeft, rfid)
  148. }
  149. controlKeyBuckle(false, key.isLeft, dockBean.addr.toInt() - 1)
  150. } else {
  151. // TODO 开钥匙卡扣
  152. controlKeyBuckle(true, key.isLeft, dockBean.addr.toInt() - 1)
  153. }
  154. }
  155. }
  156. }
  157. /**
  158. * 更新状态
  159. */
  160. fun updateStatus(byteArray: ByteArray): DockBean? {
  161. if (byteArray.isEmpty()) {
  162. return null
  163. }
  164. val dockB = dockList.find { it.addr == byteArray[0] }
  165. return dockB?.parseStatus(byteArray) ?: let {
  166. val temp = DockBean(byteArray[0], null, mutableListOf())
  167. dockList.add(temp)
  168. temp.parseStatus(byteArray)
  169. }
  170. }
  171. /**
  172. * 读取设备类型
  173. */
  174. fun readDeviceType(done: ((res: List<ByteArray>) -> Unit)? = null) {
  175. modBusManager?.sendToAll(MBFrame.READ_DEVICE_TYPE) { res ->
  176. done?.invoke(res)
  177. }
  178. }
  179. /**
  180. * 更新设备类型
  181. */
  182. fun updateDeviceType(idx: Byte?, type: Byte?) {
  183. dockList.find { it.addr == idx }?.type = type
  184. }
  185. /**
  186. * 读取卡扣状态
  187. *
  188. * @param isLock true:读锁具底座 false:读钥匙底座
  189. * @param type 0:钥匙底座 1:锁具底座1-8 2:锁具底座9、10
  190. */
  191. fun readBuckleStatus(isLock: Boolean, slaveIdx: Int?, doneSingle: ((type: Int, res: ByteArray) -> Unit)? = null) {
  192. // TODO 电磁锁控制板可能不是,并且锁和钥匙的读取不一样
  193. slaveIdx?.let {
  194. modBusManager?.sendTo(it, MBFrame.READ_BUCKLE_STATUS) { res ->
  195. doneSingle?.invoke(if (isLock) 1 else 0, res)
  196. }
  197. if (isLock) {
  198. modBusManager?.sendTo(it, MBFrame.READ_LOCK_BUCKLE_EXTRA_STATUS) { res ->
  199. doneSingle?.invoke(2, res)
  200. }
  201. }
  202. }
  203. }
  204. /**
  205. * 开/关锁具卡扣
  206. */
  207. fun controlLockBuckle(isOpen: Boolean, slaveIdx: Int?, lockIdx: Int, done: ((res: ByteArray) -> Unit)? = null) {
  208. slaveIdx?.let {
  209. modBusManager?.generateLockBuckleCmd(isOpen, lockIdx)?.let { cmd ->
  210. modBusManager?.sendTo(it, cmd) { res ->
  211. done?.invoke(res)
  212. }
  213. }
  214. }
  215. }
  216. fun controlLockBuckle(isOpen: Boolean, slaveIdx: Int?, lockIdxList: MutableList<Int>, done: ((res: ByteArray) -> Unit)? = null) {
  217. slaveIdx?.let {
  218. modBusManager?.generateLockBuckleCmd(isOpen, lockIdxList)?.let { cmdList ->
  219. cmdList.forEach { cmd ->
  220. modBusManager?.sendTo(it, cmd) { res ->
  221. done?.invoke(res)
  222. }
  223. }
  224. }
  225. }
  226. }
  227. /**
  228. * 读取钥匙RFID
  229. */
  230. fun readKeyRfid(slaveIdx: Int?, idx: Int, done: ((isLeft: Boolean, res: ByteArray) -> Unit)? = null) {
  231. slaveIdx?.let {
  232. modBusManager?.generateRfidCmd(idx)?.let { cmd ->
  233. modBusManager?.sendTo(it, cmd) {
  234. done?.invoke(idx == 0, it)
  235. }
  236. }
  237. }
  238. }
  239. /**
  240. * 读取锁具RFID
  241. */
  242. fun readLockRfid(slaveIdx: Int?, lockIdx: Int, done: ((res: ByteArray) -> Unit)? = null) {
  243. slaveIdx?.let {
  244. modBusManager?.generateRfidCmd(lockIdx)?.let { cmd ->
  245. modBusManager?.sendTo(it, cmd) { res ->
  246. done?.invoke(res)
  247. }
  248. }
  249. }
  250. }
  251. /**
  252. * 读便携式底座卡RFID
  253. */
  254. fun readPortalCaseCardRfid(slaveIdx: Int?, done: ((res: ByteArray) -> Unit)? = null) {
  255. slaveIdx?.let {
  256. modBusManager?.generateRfidCmd(8)?.let { cmd ->
  257. modBusManager?.sendTo(it, cmd) { res ->
  258. done?.invoke(res)
  259. }
  260. }
  261. }
  262. }
  263. /**
  264. * 更新钥匙RFID
  265. */
  266. fun updateKeyRfid(slaveIdx: Int, isLeft: Boolean, rfid: String) {
  267. dockList.find { it.addr.toInt() == slaveIdx }?.getKeyList()?.find { it.isLeft == isLeft }?.rfid = rfid
  268. }
  269. /**
  270. * 通过RFID更新对应的Mac
  271. */
  272. fun updateKeyMacByRfid(rfid: String, mac: String) {
  273. dockList.find { it.type == DOCK_TYPE_KEY }?.getKeyList()?.find { it.rfid == rfid }?.mac = mac
  274. }
  275. /**
  276. * 更新锁具RFID
  277. */
  278. fun updateLockRfid(slaveIdx: Int, lockIdx: Int, rfid: String) {
  279. dockList.find { it.addr.toInt() == slaveIdx }?.getLockList()?.find { it.idx == lockIdx }?.rfid = rfid
  280. }
  281. /**
  282. * 操作钥匙灯
  283. *
  284. * @param leftAction、rightAction 0:保持当前状态 1:点亮 2:熄灭 默认0
  285. */
  286. fun controlKeyLight(slaveIdx: Int?, leftAction: Int = 0, rightAction: Int = 0, done: ((res: ByteArray) -> Unit)? = null) {
  287. slaveIdx?.let {
  288. modBusManager?.generateKeyLightCmd(leftAction, rightAction)?.let { cmd ->
  289. modBusManager?.sendTo(it, cmd) {
  290. done?.invoke(it)
  291. }
  292. }
  293. }
  294. }
  295. /**
  296. * 开/关钥匙卡扣
  297. *
  298. * @param isOpen true:开操作 false:关操作
  299. * @param isLeft true:左卡扣 false:右卡扣
  300. */
  301. fun controlKeyBuckle(isOpen: Boolean, isLeft: Boolean, slaveIdx: Int?, done: ((res: ByteArray) -> Unit)? = null) {
  302. slaveIdx?.let {
  303. modBusManager?.generateKeyBuckleCmd(isOpen, if (isLeft) 0 else 1)?.let { cmd ->
  304. modBusManager?.sendTo(it, cmd) { res ->
  305. done?.invoke(res)
  306. }
  307. }
  308. }
  309. }
  310. /**
  311. * 根据RFID找钥匙
  312. */
  313. fun getKeyByRfid(rfid: String): DockBean.KeyBean? {
  314. return dockList.find { it.type == DOCK_TYPE_KEY }?.getKeyList()?.find { it.rfid == rfid }
  315. }
  316. /**
  317. * 根据RFID找锁具
  318. */
  319. fun getLockByRfid(rfid: String): DockBean.LockBean? {
  320. return dockList.find { it.type == DOCK_TYPE_LOCK }?.getLockList()?.find { it.rfid == rfid }
  321. }
  322. fun openAllLockBuckles() {
  323. dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }.forEach { dockBean ->
  324. val list = dockBean.getLockList().stream().map { it.idx }.collect(Collectors.toList())
  325. controlLockBuckle(true, dockBean.addr.toInt() - 1, list) {
  326. LogUtil.i("开所有锁卡扣 : ${it.toHexStrings()}")
  327. }
  328. }
  329. }
  330. fun closeAllLockBuckles() {
  331. dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }.forEach { dockBean ->
  332. val list = dockBean.getLockList().stream().map { it.idx }.collect(Collectors.toList())
  333. controlLockBuckle(false, dockBean.addr.toInt() - 1, list) {
  334. LogUtil.i("关所有锁卡扣 : ${it.toHexStrings()}")
  335. }
  336. }
  337. }
  338. fun printDockInfo() {
  339. println("当前底座列表 : $dockList")
  340. dockList.forEach { dockBean ->
  341. when (dockBean.type) {
  342. DOCK_TYPE_LOCK -> {
  343. dockBean.getLockList().forEach { lockBean ->
  344. println("${dockBean.addr}锁${lockBean.idx} : ${lockBean.rfid}")
  345. }
  346. }
  347. DOCK_TYPE_KEY -> {
  348. dockBean.getKeyList().forEach { keyBean ->
  349. println("${dockBean.addr}钥${keyBean.idx} : ${keyBean.rfid}")
  350. }
  351. }
  352. DOCK_TYPE_PORTABLE -> {
  353. dockBean.getLockList().forEach { lockBean ->
  354. println("${dockBean.addr}柜锁${lockBean.idx} : ${lockBean.rfid}")
  355. }
  356. dockBean.getKeyList().forEach { keyBean ->
  357. println("${dockBean.addr}柜钥${keyBean.idx} : ${keyBean.rfid}")
  358. }
  359. }
  360. }
  361. }
  362. }
  363. fun updateDeviceType() {
  364. println("____________________________________")
  365. readDeviceType { res ->
  366. LogUtil.i("设备类型数量 : ${res.size}")
  367. LogUtil.i("设备类型 : ${res.map { it.toHexStrings()}}")
  368. res.forEach { bytes ->
  369. if (bytes.size < 5) return@forEach
  370. // 设备具体数据由0x0011寄存器提供
  371. updateDeviceType(bytes[0], bytes[4])
  372. val type = when (bytes[4]) {
  373. DOCK_TYPE_KEY -> "钥匙底座"
  374. DOCK_TYPE_LOCK -> "锁具底座"
  375. DOCK_TYPE_ELEC_LOCK_BOARD -> "电磁锁控制板"
  376. DOCK_TYPE_PORTABLE -> "便携式底座"
  377. else -> "未知"
  378. }
  379. LogUtil.i("设备(${bytes[0].toInt()})类型:$type")
  380. }
  381. println("____________________________________")
  382. }
  383. }
  384. }