BusinessManager.kt 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. package com.grkj.iscs
  2. import android.bluetooth.BluetoothGatt
  3. import android.os.Build
  4. import android.util.Log
  5. import androidx.appcompat.app.AppCompatActivity
  6. import com.clj.fastble.BleManager
  7. import com.clj.fastble.data.BleDevice
  8. import com.clj.fastble.exception.BleException
  9. import com.google.gson.Gson
  10. import com.grkj.iscs.base.BaseActivity
  11. import com.grkj.iscs.ble.BleBean
  12. import com.grkj.iscs.ble.BleCmdManager
  13. import com.grkj.iscs.ble.BleConst
  14. import com.grkj.iscs.ble.BleConst.REQ_WORK_TICKET_RESULT_PART
  15. import com.grkj.iscs.ble.BleConst.STATUS_READY
  16. import com.grkj.iscs.ble.BleConst.STATUS_WORK
  17. import com.grkj.iscs.ble.BleUtil
  18. import com.grkj.iscs.ble.CustomBleGattCallback
  19. import com.grkj.iscs.ble.CustomBleIndicateCallback
  20. import com.grkj.iscs.ble.CustomBleScanCallback
  21. import com.grkj.iscs.ble.CustomBleWriteCallback
  22. import com.grkj.iscs.dialog.TipDialog
  23. import com.grkj.iscs.extentions.removeLeadingZeros
  24. import com.grkj.iscs.extentions.serialNo
  25. import com.grkj.iscs.extentions.startsWith
  26. import com.grkj.iscs.extentions.toByteArray
  27. import com.grkj.iscs.extentions.toHexStrings
  28. import com.grkj.iscs.modbus.DockBean
  29. import com.grkj.iscs.modbus.ModBusController
  30. import com.grkj.iscs.model.Constants
  31. import com.grkj.iscs.model.Constants.PERMISSION_REQUEST_CODE
  32. import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_CARD
  33. import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_FINGERPRINT
  34. import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_KEY
  35. import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_LOCK
  36. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_ELEC_LOCK_BOARD
  37. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_KEY
  38. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_LOCK
  39. import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_PORTABLE
  40. import com.grkj.iscs.model.bo.WorkTicketGetBO
  41. import com.grkj.iscs.model.bo.WorkTicketSendBO
  42. import com.grkj.iscs.model.vo.ticket.LockPointUpdateReqVO
  43. import com.grkj.iscs.model.vo.ticket.TicketDetailRespVO
  44. import com.grkj.iscs.presentation.PresentationManager
  45. import com.grkj.iscs.util.ActivityUtils
  46. import com.grkj.iscs.util.CommonUtils
  47. import com.grkj.iscs.util.Executor
  48. import com.grkj.iscs.util.NetApi
  49. import com.grkj.iscs.util.SPUtils
  50. import com.grkj.iscs.util.ToastUtils
  51. import com.grkj.iscs.util.log.LogUtil
  52. import pub.devrel.easypermissions.AfterPermissionGranted
  53. /**
  54. * 业务层管理
  55. */
  56. object BusinessManager {
  57. var NEED_AUTH = true
  58. // 归还设备是否需要登录及角色验证
  59. private var CAN_RETURN = true
  60. get() {
  61. // TODO 临时注掉,方便调试
  62. val loginUser = SPUtils.getLoginUser(MyApplication.instance!!.applicationContext!!)
  63. return (NEED_AUTH && loginUser != null) || !NEED_AUTH
  64. }
  65. /****************************************** ModBus ******************************************/
  66. fun connectDock(isNeedInit: Boolean = false) {
  67. // 暂定100上限
  68. // TODO demo为了快用3个
  69. ModBusController.setSlaveCount(3)
  70. ModBusController.interruptReadTrashBinStatus(false)
  71. ModBusController.start(MyApplication.instance!!.applicationContext)
  72. // ModBusController.unregisterListener(MyApplication.instance!!.applicationContext)
  73. if (isNeedInit) {
  74. ModBusController.initDevicesStatus()
  75. }
  76. }
  77. fun disconnectDock() {
  78. ModBusController.stop()
  79. }
  80. class DeviceListener(
  81. val key: Any,
  82. val callBack: (DockBean) -> Unit
  83. )
  84. private val listeners = ArrayList<DeviceListener>()
  85. fun registerStatusListener(key: Any, listener: (DockBean) -> Unit) {
  86. listeners.add(DeviceListener(key, listener))
  87. }
  88. fun unregisterListener(key: Any) {
  89. val it = listeners.iterator()
  90. while (it.hasNext()) {
  91. if (it.next().key == key) {
  92. it.remove()
  93. }
  94. }
  95. }
  96. /**
  97. * 总的监听,做预处理,其余的所有监听均使用本监听处理后的数据,只允许调用一次
  98. */
  99. fun registerMainListener() {
  100. ModBusController.registerStatusListener(this) { res ->
  101. LogUtil.i("设备状态:${(res as List<ByteArray>).map { it.toHexStrings() }}")
  102. res.forEach { bytes ->
  103. val dockBean = ModBusController.updateStatus(bytes) ?: return@forEach
  104. // if (!CAN_RETURN) {
  105. // return@forEach
  106. // }
  107. when (dockBean.type) {
  108. DOCK_TYPE_KEY -> {
  109. dockBean.deviceList.forEach { keyBean ->
  110. if (keyBean.isExist) {
  111. // 放回钥匙,读取rfid
  112. ModBusController.readKeyRfid(dockBean.addr.toInt() - 1, if ((keyBean as DockBean.KeyBean).isLeft) 0 else 1) { isLeft, res ->
  113. val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  114. ModBusController.updateKeyRfid(dockBean.addr.toInt(), keyBean.isLeft, rfid)
  115. if (PresentationManager.mConfigKeyList.any { it.rfid == rfid }) {
  116. val mac = PresentationManager.mConfigKeyList.find { it.rfid == rfid }?.keyMac
  117. ModBusController.updateKeyMac(dockBean.addr.toInt(), keyBean.isLeft, mac!!)
  118. }
  119. // NetApi.getKeyInfo(rfid) {
  120. // if (it != null && !it.macAddress.isNullOrEmpty()) {
  121. // ModBusController.updateKeyMac(dockBean.addr.toInt(), keyBean.isLeft, it.macAddress)
  122. // showKeyReturnDialog(it.macAddress, isLeft, dockBean.addr.toInt())
  123. // } else {
  124. // ToastUtils.tip(R.string.get_key_info_fail)
  125. // }
  126. // }
  127. // TODO 蓝牙通信
  128. }
  129. // ModBusController.controlKeyBuckle(false, isLeft = true, dockBean.addr.toInt() - 1)
  130. }
  131. }
  132. }
  133. DOCK_TYPE_LOCK -> {
  134. dockBean.deviceList.forEach { lockBean ->
  135. if (lockBean.isExist) {
  136. ModBusController.readLockRfid(dockBean.addr.toInt() - 1, lockBean.idx) { res ->
  137. val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  138. ModBusController.updateLockRfid(dockBean.addr.toInt(), lockBean.idx, rfid)
  139. // NetApi.getLockInfo(rfid) {
  140. // if (it != null) {
  141. // TODO 考虑快速拿取
  142. ModBusController.controlLockBuckle(false, dockBean.addr.toInt() - 1, lockBean.idx) { itRst ->
  143. if (itRst.isNotEmpty()) {
  144. // 上报锁具信息
  145. // NetApi.updateLockReturn(rfid, MyApplication.instance!!.serialNo()) {}
  146. }
  147. }
  148. // }
  149. // }
  150. }
  151. }
  152. }
  153. }
  154. DOCK_TYPE_ELEC_LOCK_BOARD -> {
  155. // TODO 占位
  156. }
  157. DOCK_TYPE_PORTABLE -> {
  158. // TODO 便携式待完善
  159. dockBean.deviceList.forEach { deviceBean ->
  160. if (deviceBean.isExist) {
  161. when (deviceBean.type) {
  162. DEVICE_TYPE_KEY -> {
  163. ModBusController.readKeyRfid(dockBean.addr.toInt() - 1, deviceBean.idx) { isLeft, res ->
  164. val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  165. ModBusController.updateKeyRfid(dockBean.addr.toInt(), true, rfid)
  166. NetApi.getKeyInfo(rfid) {
  167. if (it != null && !it.macAddress.isNullOrEmpty()) {
  168. ModBusController.updateKeyMac(dockBean.addr.toInt(), isLeft, it.macAddress)
  169. showKeyReturnDialog(it.macAddress, isLeft, dockBean.addr.toInt())
  170. } else {
  171. ToastUtils.tip(R.string.get_key_info_fail)
  172. }
  173. }
  174. // TODO 蓝牙通信
  175. }
  176. // ModBusController.controlKeyBuckle(false, isLeft = true, dockBean.addr.toInt() - 1)
  177. }
  178. DEVICE_TYPE_LOCK -> {
  179. ModBusController.readLockRfid(dockBean.addr.toInt() - 1, deviceBean.idx) { res ->
  180. val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  181. ModBusController.updateLockRfid(dockBean.addr.toInt(), deviceBean.idx, rfid)
  182. NetApi.getLockInfo(rfid) {
  183. if (it != null) {
  184. // TODO 考虑快速拿取
  185. ModBusController.controlLockBuckle(false, dockBean.addr.toInt() - 1, deviceBean.idx) { itRst ->
  186. if (itRst.isNotEmpty()) {
  187. // 上报锁具信息
  188. NetApi.updateLockReturn(rfid, MyApplication.instance!!.serialNo()) {}
  189. }
  190. }
  191. }
  192. }
  193. }
  194. }
  195. DEVICE_TYPE_CARD -> {
  196. ModBusController.readPortalCaseCardRfid(dockBean.addr.toInt() - 1) { res ->
  197. val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
  198. println("卡片RFID : $rfid")
  199. }
  200. }
  201. DEVICE_TYPE_FINGERPRINT -> {
  202. }
  203. }
  204. }
  205. }
  206. }
  207. }
  208. Executor.delayOnMain(200) {
  209. listeners.forEach { it.callBack(dockBean) }
  210. }
  211. }
  212. }
  213. }
  214. /**
  215. * 钥匙归还提示确认弹框
  216. */
  217. private fun showKeyReturnDialog(mac: String, isLeft: Boolean, slaveIdx: Int) {
  218. val dlg = TipDialog(MyApplication.instance!!.applicationContext)
  219. dlg.setTip(MyApplication.instance!!.getString(R.string.key_return_tip))
  220. dlg.setType(TipDialog.TYPE_CONFIRM)
  221. dlg.setConfirmListener {
  222. ModBusController.controlKeyBuckle(false, isLeft, slaveIdx)
  223. getTicketStatusBusiness(mac, ActivityUtils.currentActivity() as BaseActivity<*>) { b, s, rst ->
  224. (ActivityUtils.currentActivity() as BaseActivity<*>).handleLoading(b, s)
  225. }
  226. }
  227. }
  228. fun readLockBuckleStatus() {
  229. // TODO slaveIdx暂时写死,调试用
  230. ModBusController.readBuckleStatus(true, 0) { type, res ->
  231. LogUtil.i("单slave卡扣状态 : $type - ${res.toHexStrings()}")
  232. when (type) {
  233. 0 -> {
  234. val isLeftLock = (res[4].toInt() shr 0) and 0x1 == 1
  235. val isRightLock = (res[4].toInt() shr 4) and 0x1 == 1
  236. println("锁具底座卡扣状态 : $isLeftLock - $isRightLock")
  237. }
  238. 1 -> {
  239. val tempList = mutableListOf<Boolean>()
  240. for (i in 0..7) {
  241. tempList.add((res[4].toInt() shr i) and 0x1 == 1)
  242. }
  243. println("锁具底座卡扣1-8状态 : $tempList")
  244. }
  245. 2 -> {
  246. val lock9Status = (res[4].toInt() shr 0) and 0x1 == 1
  247. val lock10Status = (res[4].toInt() shr 1) and 0x1 == 1
  248. println("锁具底座卡扣9、10状态 : $lock9Status - $lock10Status")
  249. }
  250. }
  251. }
  252. }
  253. fun readKeyBuckleStatus() {
  254. // TODO slaveIdx暂时写死,调试用
  255. ModBusController.readBuckleStatus(false, 1) { type, res ->
  256. LogUtil.i("单slave卡扣状态 : $type - ${res.toHexStrings()}")
  257. // TODO 待验证
  258. when (type) {
  259. 0 -> {
  260. val isLeftLock = (res[4].toInt() shr 0) and 0x1 == 1
  261. val isRightLock = (res[4].toInt() shr 4) and 0x1 == 1
  262. println("钥匙底座卡扣状态 : $isLeftLock - $isRightLock")
  263. }
  264. 1 -> {
  265. val tempList = mutableListOf<Boolean>()
  266. for (i in 0..7) {
  267. tempList.add((res[4].toInt() shr i) and 0x1 == 1)
  268. }
  269. println("锁具底座卡扣1-8状态 : $tempList")
  270. }
  271. 2 -> {
  272. val lock9Status = (res[4].toInt() shr 0) and 0x1 == 1
  273. val lock10Status = (res[4].toInt() shr 1) and 0x1 == 1
  274. println("锁具底座卡扣9、10状态 : $lock9Status - $lock10Status")
  275. }
  276. }
  277. }
  278. }
  279. /**
  280. * 检查钥匙和锁具数量
  281. *
  282. * @param needLockCount 需要的锁具的数量(可能在别的机柜取过)
  283. */
  284. fun checkEquipCount(needLockCount: Int, callBack: (Pair<Byte, DockBean.KeyBean?>?, MutableMap<Byte, MutableList<DockBean.LockBean>>) -> Unit) {
  285. var lockCount = 0
  286. val lockMap = ModBusController.getLocks(needLockCount)
  287. lockMap.forEach { (_, rfidList) ->
  288. lockCount += rfidList.size
  289. }
  290. val key = ModBusController.getOneKey()
  291. var tipStr = ""
  292. println("checkEquipCount : $lockCount - $needLockCount")
  293. if (lockCount < needLockCount) {
  294. val msg = MyApplication.instance!!.applicationContext.resources.getString(R.string.lock_is_not_enough)
  295. LogUtil.w(msg)
  296. tipStr = msg
  297. }
  298. if (key == null) {
  299. val msg = MyApplication.instance!!.applicationContext.resources.getString(R.string.key_is_not_enough)
  300. LogUtil.w(msg)
  301. tipStr = if (tipStr.isEmpty()) {
  302. msg
  303. } else {
  304. tipStr + "\n" + msg
  305. }
  306. }
  307. if (tipStr.isNotEmpty()) {
  308. ToastUtils.tip(tipStr)
  309. }
  310. callBack.invoke(if (lockCount < needLockCount) null else key, lockMap)
  311. }
  312. /****************************************** 蓝牙 ******************************************/
  313. /******************************************蓝牙通用准备******************************************/
  314. fun prepareBle(
  315. mac: String,
  316. activity: AppCompatActivity,
  317. loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?,
  318. prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
  319. ) {
  320. Executor.runOnMain {
  321. CommonUtils.checkBlePermission(activity) {
  322. doScanBle(mac, loadingCallBack, prepareDoneCallBack)
  323. }
  324. }
  325. }
  326. @AfterPermissionGranted(PERMISSION_REQUEST_CODE)
  327. fun doScanBle(mac: String, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?, prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?) {
  328. LogUtil.d("扫描开始:$mac")
  329. loadingCallBack?.invoke(true, MyApplication.instance?.getString(R.string.start_scanning_for_devices), null)
  330. BleUtil.instance?.scan(object : CustomBleScanCallback() {
  331. override fun onPrompt(promptStr: String?) {
  332. BleManager.getInstance().enableBluetooth()
  333. }
  334. override fun onScanStarted(success: Boolean) {
  335. LogUtil.d("扫描开始:${success}")
  336. // BleUtil.instance?.deviceList?.clear()
  337. }
  338. override fun onScanning(bleDevice: BleDevice?) {
  339. bleDevice?.let {
  340. Log.d("doScanBle", "扫描到的设备:${it.mac}")
  341. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
  342. if (!it.name.isNullOrBlank()) {
  343. // BleUtil.instance?.deviceList?.add(BleBean(it))
  344. } else {
  345. }
  346. } else {
  347. // BleUtil.instance?.deviceList?.add(BleBean(it))
  348. }
  349. }
  350. }
  351. override fun onScanFinished(scanResultList: MutableList<BleDevice>?) {
  352. loadingCallBack?.invoke(false, null, null)
  353. // if (BleUtil.instance?.deviceList?.isEmpty() == true) {
  354. // ToastUtils.tip(R.string.ble_no_device_found)
  355. // loadingCallBack?.invoke(false, null, false)
  356. // return
  357. // }
  358. // BleUtil.instance?.getBleDeviceByMac(mac)?.bleDevice?.let {
  359. // doConnect(it, loadingCallBack, prepareDoneCallBack)
  360. // }
  361. scanResultList?.find { it.mac == mac }?.let {
  362. doConnect(it, loadingCallBack, prepareDoneCallBack)
  363. }
  364. }
  365. })
  366. }
  367. /**
  368. * 连接蓝牙设备
  369. */
  370. fun doConnect(
  371. bleDevice: BleDevice,
  372. loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?,
  373. prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
  374. ) {
  375. loadingCallBack?.invoke(true, CommonUtils.getStr(R.string.ble_connecting), null)
  376. BleManager.getInstance().disconnect(bleDevice)
  377. BleUtil.instance?.connectBySelect(bleDevice,
  378. object : CustomBleGattCallback() {
  379. override fun onPrompt(promptStr: String?) {
  380. loadingCallBack?.invoke(false, promptStr, false)
  381. }
  382. override fun onStartConnect() {}
  383. override fun onConnectFail(bleDevice: BleDevice?, exception: BleException?) {
  384. loadingCallBack?.invoke(false, CommonUtils.getStr(R.string.ble_connect_fail), false)
  385. prepareDoneCallBack?.invoke(false, null)
  386. }
  387. override fun onConnectSuccess(bleDevice: BleDevice?, gatt: BluetoothGatt?, status: Int) {
  388. loadingCallBack?.invoke(false, null, null)
  389. LogUtil.i("onConnectSuccess : $bleDevice")
  390. bleDevice?.let {
  391. val bleBean = BleBean(it)
  392. ToastUtils.tip(R.string.connect_success)
  393. BleUtil.instance?.deviceList?.add(bleBean)
  394. // 设置MTU
  395. Executor.delayOnMain(200) {
  396. BleUtil.instance?.setMtu(it)
  397. }
  398. // 监听
  399. Executor.delayOnMain(500) {
  400. indicate(bleBean, loadingCallBack, prepareDoneCallBack)
  401. }
  402. }
  403. }
  404. override fun onDisConnected(isActiveDisConnected: Boolean, device: BleDevice?, gatt: BluetoothGatt?, status: Int) {
  405. loadingCallBack?.invoke(false, null, false)
  406. ToastUtils.tip(CommonUtils.getStr(R.string.ble_disconnect))
  407. BleUtil.instance?.getBleDeviceByMac(device?.mac)?.let {
  408. BleUtil.instance?.deviceList?.remove(it)
  409. }
  410. }
  411. })
  412. }
  413. /**
  414. * 监听蓝牙设备
  415. */
  416. private fun indicate(
  417. bleBean: BleBean?,
  418. loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?,
  419. prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
  420. ) {
  421. loadingCallBack?.invoke(true, MyApplication.instance?.getString(R.string.start_indicating), null)
  422. bleBean?.let {
  423. BleUtil.instance?.indicate(it.bleDevice, indicateCallback = object : CustomBleIndicateCallback() {
  424. override fun onPrompt(promptStr: String?) {
  425. LogUtil.i("监听onPrompt : $promptStr")
  426. }
  427. override fun onConnectPrompt(promptStr: String?) {
  428. LogUtil.i("监听onConnectPrompt : $promptStr")
  429. }
  430. override fun onDisConnectPrompt(promptStr: String?) {
  431. LogUtil.i("监听onDisConnectPrompt : $promptStr")
  432. }
  433. override fun onIndicateSuccess() {
  434. LogUtil.i("监听成功")
  435. // val testStr = "{\"cardNo\":\"80A8C0F4EA\",\"password\":\"12345678\",\"effectiveTime\":24,\"data\":[{\"taskCode\":\"202401020001\",\"taskId\":\"71b49baa49b343bc84d7e6b829ac1bdc\",\"codeId\":1,\"dataList\":[{\"dataId\":1,\"equipRfidNo\":\"049648B2E31690\",\"infoRfidNo\":\"04E3BCCA201290\",\"target\":1},{\"dataId\":2,\"equipRfidNo\":\"0405982414C563\",\"target\":0,\"prevId\":1}]},{\"taskCode\":\"202401020002\",\"taskId\":\"145b5a4cc38c41e19943f4c8b48d12b0\",\"codeId\":2,\"dataList\":[{\"dataId\":1,\"equipRfidNo\":\"045460F7F4F438\",\"infoRfidNo\":\"04BC6584C65009\",\"target\":1},{\"dataId\":2,\"equipRfidNo\":\"042B99E449E795\",\"target\":0,\"prevId\":1},{\"dataId\":3,\"equipRfidNo\":\"04A312EE848B62\",\"infoRfidNo\":\"04220E86831289\",\"target\":1,\"prevId\":2}]}],\"lockList\":[{\"lockId\":\"1\",\"rfid\":\"040E21443010E9\"},{\"lockId\":\"2\",\"rfid\":\"0457505E5861C2\"}]}"
  436. // sendTicket(testStr, it.bleDevice, loadingCallBack)
  437. getToken(bleBean, loadingCallBack, prepareDoneCallBack)
  438. }
  439. override fun onIndicateFailure(exception: BleException?) {
  440. loadingCallBack?.invoke(false, null, false)
  441. ToastUtils.tip(MyApplication.instance?.getString(R.string.indicate_fail))
  442. LogUtil.i("监听失败")
  443. prepareDoneCallBack?.invoke(false, null)
  444. }
  445. override fun onCharacteristicChanged(data: ByteArray?) {
  446. LogUtil.i("监听数据 : ${data?.toHexStrings()}")
  447. data?.let { itData ->
  448. handleRsp(it, itData, loadingCallBack)
  449. }
  450. }
  451. })
  452. }
  453. }
  454. /**
  455. * 获取蓝牙钥匙token
  456. */
  457. private fun getToken(
  458. bleBean: BleBean?,
  459. loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?,
  460. prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
  461. ) {
  462. loadingCallBack?.invoke(true, MyApplication.instance?.getString(R.string.start_getting_token), null)
  463. bleBean?.let {
  464. BleCmdManager.getToken(it.bleDevice.mac, object : CustomBleWriteCallback() {
  465. override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
  466. loadingCallBack?.invoke(false, MyApplication.instance?.getString(R.string.get_token_success), null)
  467. LogUtil.i("getToken success : ${bleBean.bleDevice.mac}")
  468. prepareDoneCallBack?.invoke(true, bleBean)
  469. }
  470. override fun onWriteFailure(exception: BleException?) {
  471. loadingCallBack?.invoke(false, MyApplication.instance?.getString(R.string.get_token_fail), false)
  472. LogUtil.e("getToken fail : ${bleBean.bleDevice.mac}")
  473. prepareDoneCallBack?.invoke(false, null)
  474. }
  475. })
  476. }
  477. }
  478. /******************************************蓝牙通用准备结束******************************************/
  479. /**
  480. * 下发工作票
  481. * TODO 演示demo专用
  482. * @param loadingCallBack 是否显示loading、提示信息、是否结束(true成功结束、false失败结束、null继续执行)
  483. */
  484. fun sendTicketBusiness(
  485. mac: String,
  486. activity: AppCompatActivity,
  487. loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?
  488. ) {
  489. // prepareBle(mac, activity, loadingCallBack) { done, bleBean ->
  490. // if (done) {
  491. // Executor.delayOnMain(500) {
  492. // TODO 蓝牙准备操作
  493. val bleBean = BleUtil.instance?.getBleDeviceByMac(mac)
  494. if (bleBean == null) {
  495. ToastUtils.tip(R.string.simple_key_is_not_connected)
  496. return
  497. }
  498. // 单bleBean json赋值
  499. bleBean?.ticketSend = PresentationManager.getSimpleTicketJson()
  500. bleBean?.ticketSend?.let { itJson ->
  501. sendTicket(itJson, bleBean.bleDevice, loadingCallBack)
  502. }
  503. // }
  504. // } else {
  505. // loadingCallBack?.invoke(false, null, false)
  506. // }
  507. // }
  508. }
  509. /**
  510. * 下发工作票
  511. */
  512. fun sendTicketBusiness(
  513. mac: String,
  514. ticketDetail: TicketDetailRespVO,
  515. activity: AppCompatActivity,
  516. loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?,
  517. ) {
  518. prepareBle(mac, activity, loadingCallBack) { done, bleBean ->
  519. if (done) {
  520. Executor.delayOnMain(500) {
  521. // 单bleBean json赋值
  522. bleBean?.ticketSend = generateTicketSendJson(ticketDetail)
  523. bleBean?.ticketSend?.let { itJson ->
  524. sendTicket(itJson, bleBean.bleDevice, loadingCallBack)
  525. }
  526. }
  527. } else {
  528. loadingCallBack?.invoke(false, null, false)
  529. }
  530. }
  531. }
  532. /**
  533. * 读取工作票完成情况
  534. */
  535. fun getTicketStatusBusiness(mac: String, activity: AppCompatActivity, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) {
  536. prepareBle(mac, activity, loadingCallBack) { done, bleBean ->
  537. if (done) {
  538. Executor.delayOnMain(500) {
  539. // // TODO 蓝牙准备操作
  540. // val bleBean = BleUtil.instance?.getBleDeviceByMac(mac)
  541. // if (bleBean == null) {
  542. // ToastUtils.tip(R.string.simple_key_is_not_connected)
  543. // return
  544. // }
  545. getTicketStatus(bleBean!!.bleDevice, loadingCallBack)
  546. }
  547. } else {
  548. loadingCallBack?.invoke(false, null, false)
  549. }
  550. }
  551. }
  552. private fun sendTicket(jsonStr: String, bleDevice: BleDevice, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) {
  553. val ctx = MyApplication.instance!!
  554. loadingCallBack?.invoke(true, ctx.getString(R.string.simple_start_send_ticket), null)
  555. BleCmdManager.sendWorkTicket(jsonStr, bleDevice = bleDevice, callback = object : CustomBleWriteCallback() {
  556. override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
  557. println("sendTicket success")
  558. loadingCallBack?.invoke(true, ctx.getString(R.string.simple_sending_ticket), null)
  559. }
  560. override fun onWriteFailure(exception: BleException?) {
  561. LogUtil.e("sendTicket fail : ${bleDevice.mac}")
  562. loadingCallBack?.invoke(false, ctx.getString(R.string.simple_send_ticket_fail), null)
  563. }
  564. })
  565. }
  566. /**
  567. * 生成下发工作票Json
  568. *
  569. * @param vo 工作票详情
  570. */
  571. private fun generateTicketSendJson(vo: TicketDetailRespVO): String {
  572. // 用ticketStatus的"待上锁"进行判断
  573. val isLock = vo.ticketStatus == Constants.TICKET_STATUS_READY_TO_LOCK
  574. val bo = WorkTicketSendBO(
  575. cardNo = SPUtils.getLoginUser(MyApplication.instance!!.applicationContext)?.cardNfc,
  576. )
  577. CommonUtils.getDiffHours(vo.ticketEndTime)?.let {
  578. bo.effectiveTime = it
  579. }
  580. val dataBO = WorkTicketSendBO.DataBO(
  581. taskCode = vo.ticketCode,
  582. taskId = vo.ticketId.toString(),
  583. codeId = 1
  584. )
  585. val taskList = ArrayList<WorkTicketSendBO.DataBO.DataListBO>()
  586. vo.pointDetailVOList?.let { itList ->
  587. itList.forEach { pointVO ->
  588. val task = WorkTicketSendBO.DataBO.DataListBO(
  589. dataId = pointVO.pointId?.toInt(),
  590. equipRfidNo = pointVO.pointNfc,
  591. infoRfidNo = pointVO.pointName,
  592. target = if (isLock) 0 else 1
  593. )
  594. pointVO.prePointId?.let {
  595. task.prevId = it.toInt()
  596. }
  597. if (!isLock) {
  598. task.infoRfidNo = pointVO.lockId.toString()
  599. }
  600. // TODO partCode待补充
  601. taskList.add(task)
  602. }
  603. }
  604. dataBO.dataList = taskList
  605. bo.data = mutableListOf(dataBO)
  606. if (isLock) {
  607. bo.lockList = mutableListOf()
  608. }
  609. // TODO partList 待补充
  610. val jsonStr = Gson().toJson(bo)
  611. return jsonStr
  612. }
  613. fun handleRsp(bleBean: BleBean, byteArray: ByteArray, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) {
  614. // TODO Token校验
  615. // val len = byteArray[2].toInt()
  616. // val token = byteArray.copyOfRange(len + 7, len + 11)
  617. // if (token.contentEquals(bleBean.token)) {
  618. // LogUtil.i("Token is right")
  619. // } else {
  620. // LogUtil.e("Token is wrong")
  621. // }
  622. when {
  623. // 获取令牌
  624. byteArray.startsWith(BleConst.RSP_GET_TOKEN) -> handleToken(bleBean.bleDevice, byteArray)
  625. // 工作模式切换
  626. byteArray.startsWith(BleConst.RSP_SWITCH_MODE) -> handleSwitchModeResult(byteArray, loadingCallBack)
  627. // 工作票下发
  628. byteArray.startsWith(BleConst.RSP_SEND_WORK_TICKET) -> handleWorkTicketResult(bleBean, byteArray, loadingCallBack)
  629. // 获取设备工作票完成情况
  630. byteArray.startsWith(BleConst.RSP_WORK_TICKET_RESULT) && byteArray[3] == 0x02.toByte() ->
  631. handleTicketStatus(bleBean.bleDevice, byteArray, loadingCallBack)
  632. }
  633. }
  634. /**
  635. * 令牌处理
  636. */
  637. private fun handleToken(bleDevice: BleDevice, byteArray: ByteArray) {
  638. LogUtil.i("handleToken : ${byteArray.toHexStrings()}")
  639. BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let {
  640. it.token = byteArrayOf(byteArray[11], byteArray[12], byteArray[13], byteArray[14])
  641. println("Token 赋值 ${it.token?.toHexStrings()} : ${bleDevice.mac}")
  642. }
  643. }
  644. /**
  645. * 工作模式切换结果
  646. * job : 0x01:工作模式 0x02:待机模式
  647. * res : 0x01:成功 0x02:失败
  648. */
  649. private fun handleSwitchModeResult(byteArray: ByteArray, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) {
  650. LogUtil.i("handleSwitchModeResult : ${byteArray.toHexStrings()}")
  651. val ctx = MyApplication.instance!!
  652. val job = byteArray[4]
  653. val res = byteArray[5]
  654. loadingCallBack?.invoke(false, null, null)
  655. if (res == 0x01.toByte() && job == 0x01.toByte()) {
  656. loadingCallBack?.invoke(false, ctx.getString(R.string.simple_switch_work_mode_success), null)
  657. // TODO 切成工作模式断开,待机模式不断开
  658. BleManager.getInstance().disconnectAllDevice()
  659. } else if (res == 0x02.toByte() && job == 0x01.toByte()) {
  660. loadingCallBack?.invoke(false, ctx.getString(R.string.simple_switch_standby_mode_success), null)
  661. }
  662. }
  663. /**
  664. * 工作票下发结果
  665. * res:0x00:成功 0x01:失败 0x02:传输超时 0x0D:当前IDX超出范围 0x0E:当前数据CRC校验失败 0x14:JSON结构错误 0x63:未知错误
  666. */
  667. private fun handleWorkTicketResult(bleBean: BleBean, byteArray: ByteArray, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) {
  668. val ctx = MyApplication.instance!!
  669. LogUtil.i("handleWorkTicketResult : ${byteArray.toHexStrings()}")
  670. loadingCallBack?.invoke(false, null, null)
  671. val idx = byteArray[4] + byteArray[5]
  672. val total = byteArray[6] + byteArray[7]
  673. val res = byteArray[8]
  674. if (idx != total - 1) {
  675. if ((res == 0x00.toByte() || res == 0x02.toByte())) {
  676. // TODO 要判断res
  677. BleCmdManager.sendWorkTicket(
  678. BleUtil.instance?.getBleDeviceByMac(bleBean.bleDevice.mac)?.ticketSend!!,
  679. if (res == 0x00.toByte()) idx + 1 else idx,
  680. bleBean.bleDevice,
  681. object : CustomBleWriteCallback() {
  682. override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {}
  683. override fun onWriteFailure(exception: BleException?) {}
  684. })
  685. }
  686. } else {
  687. LogUtil.i("Work ticket is done")
  688. // 下发完毕,切换工作模式
  689. loadingCallBack?.invoke(true, ctx.getString(R.string.simple_switch_work_mode), null)
  690. BleCmdManager.switchMode(STATUS_WORK, bleBean.bleDevice, object : CustomBleWriteCallback() {
  691. override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
  692. println("switch mode 1 success")}
  693. override fun onWriteFailure(exception: BleException?) {
  694. println("switch mode 1 fail")}
  695. })
  696. // 打开钥匙卡扣
  697. val keyBean = ModBusController.getKeyByMac(bleBean.bleDevice.mac)
  698. if (keyBean == null) {
  699. loadingCallBack?.invoke(false, ctx.getString(R.string.simple_key_not_found), false)
  700. ToastUtils.tip(R.string.simple_key_not_exists)
  701. } else {
  702. loadingCallBack?.invoke(false, null, true)
  703. val dock = ModBusController.getDockByKeyMac(bleBean.bleDevice.mac)
  704. ModBusController.controlKeyBuckle(true, keyBean.isLeft, dock?.addr!!.toInt() - 1)
  705. }
  706. }
  707. }
  708. /**
  709. * 处理工作票完成情况
  710. */
  711. private fun handleTicketStatus(bleDevice: BleDevice, byteArray: ByteArray, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) {
  712. // TODO 需要有超时重传机制
  713. LogUtil.i("handleTicketStatus : ${byteArray.toHexStrings()}")
  714. val ctx = MyApplication.instance!!
  715. val total = byteArray[4] + byteArray[5]
  716. val idx = byteArray[6] + byteArray[7]
  717. val crc = byteArray[8] + byteArray[9]
  718. val size = byteArray[10].toUByte() + byteArray[11].toUByte()
  719. println("工作票数据 : $total : $idx : $size")
  720. // 数据组装
  721. BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let {
  722. it.ticketStatus += byteArray.copyOfRange(12, 12 + size.toInt())
  723. }
  724. // TODO 缺少res处理
  725. if (idx != total - 1) {
  726. loadingCallBack?.invoke(true, ctx.getString(R.string.simple_get_ticket_part), null)
  727. getTicketStatusPart((idx + 1).toByteArray(), total.toByteArray(), byteArrayOf(0x01.toByte()), bleDevice, object : CustomBleWriteCallback() {
  728. override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
  729. println("getTicketStatusPart success")
  730. }
  731. override fun onWriteFailure(exception: BleException?) {
  732. println("getTicketStatusPart fail")
  733. }
  734. })
  735. } else {
  736. loadingCallBack?.invoke(false, ctx.getString(R.string.simple_get_ticket_status_done), null)
  737. BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let {
  738. println("工作票完成接收 : ${String(it.ticketStatus)}")
  739. // TD:Ticket Done
  740. loadingCallBack?.invoke(false, "TD${String(it.ticketStatus)}", true)
  741. // TODO 清空ticket
  742. it.ticketStatus = byteArrayOf()
  743. // TODO 根据工作票完成情况,切换为待机模式
  744. BleCmdManager.switchMode(STATUS_READY, bleDevice, object : CustomBleWriteCallback() {
  745. override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
  746. println("switch mode 1 success")}
  747. override fun onWriteFailure(exception: BleException?) {
  748. println("switch mode 1 fail")}
  749. })
  750. val dock = ModBusController.getDockByKeyMac(bleDevice.mac)
  751. val keyBean = dock?.getKeyList()?.find { it.mac == bleDevice.mac }
  752. keyBean?.let {
  753. ModBusController.controlKeyBuckle(false, keyBean.isLeft, dock.addr.toInt() - 1)
  754. }
  755. // 上报隔离点状态
  756. val workTicketGetBO = Gson().fromJson(String(it.ticketStatus), WorkTicketGetBO::class.java)
  757. val keyNfc = ModBusController.getKeyByMac(bleDevice.mac)?.rfid
  758. workTicketGetBO?.data?.forEach { data ->
  759. val updateList = mutableListOf<LockPointUpdateReqVO>()
  760. data.dataList?.forEach { dataListDTO ->
  761. val updateVO = LockPointUpdateReqVO(
  762. data.taskId?.toLong(),
  763. dataListDTO.infoRfidNo,
  764. dataListDTO.equipRfidNo,
  765. keyNfc!!,
  766. dataListDTO.target,
  767. dataListDTO.status
  768. )
  769. updateList.add(updateVO)
  770. }
  771. // 上报点位钥匙绑定
  772. // NetApi.updateLockPointBatch(updateList) { itRst ->
  773. // // TODO 上报结果
  774. // }
  775. // 上报钥匙归还
  776. // NetApi.updateKeyReturn(data.taskId?.toLong()!!, keyNfc!!, MyApplication.instance!!.serialNo()) {
  777. //
  778. // }
  779. }
  780. }
  781. }
  782. }
  783. /**
  784. * 获取工作票完成情况分包
  785. */
  786. private fun getTicketStatusPart(idx: ByteArray, total: ByteArray, res: ByteArray, bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
  787. BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let {
  788. BleUtil.instance?.write(it.bleDevice, cmd = BleCmdManager.assembleData(it, REQ_WORK_TICKET_RESULT_PART + idx + total + res), writeCallback = callback)
  789. }
  790. }
  791. /**
  792. * 获取工作票完成情况
  793. */
  794. private fun getTicketStatus(bleDevice: BleDevice, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) {
  795. loadingCallBack?.invoke(true, MyApplication.instance?.getString(R.string.start_getting_ticket), null)
  796. BleCmdManager.getTicketStatus(bleDevice, object : CustomBleWriteCallback() {
  797. override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
  798. loadingCallBack?.invoke(false, MyApplication.instance?.getString(R.string.get_ticket_success), null)
  799. println("getTicketStatus success")}
  800. override fun onWriteFailure(exception: BleException?) {
  801. loadingCallBack?.invoke(false, MyApplication.instance?.getString(R.string.get_ticket_fail), false)
  802. println("getTicketStatus fail")}
  803. })
  804. }
  805. }