package com.grkj.iscs import android.bluetooth.BluetoothGatt import android.os.Build import android.util.Log import androidx.appcompat.app.AppCompatActivity import com.clj.fastble.BleManager import com.clj.fastble.data.BleDevice import com.clj.fastble.exception.BleException import com.google.gson.Gson import com.grkj.iscs.base.BaseActivity import com.grkj.iscs.ble.BleBean import com.grkj.iscs.ble.BleCmdManager import com.grkj.iscs.ble.BleConst import com.grkj.iscs.ble.BleConst.REQ_WORK_TICKET_RESULT_PART import com.grkj.iscs.ble.BleConst.STATUS_READY import com.grkj.iscs.ble.BleConst.STATUS_WORK import com.grkj.iscs.ble.BleUtil import com.grkj.iscs.ble.CustomBleGattCallback import com.grkj.iscs.ble.CustomBleIndicateCallback import com.grkj.iscs.ble.CustomBleScanCallback import com.grkj.iscs.ble.CustomBleWriteCallback import com.grkj.iscs.dialog.TipDialog import com.grkj.iscs.extentions.removeLeadingZeros import com.grkj.iscs.extentions.serialNo import com.grkj.iscs.extentions.startsWith import com.grkj.iscs.extentions.toByteArray import com.grkj.iscs.extentions.toHexStrings import com.grkj.iscs.modbus.DockBean import com.grkj.iscs.modbus.ModBusController import com.grkj.iscs.model.Constants import com.grkj.iscs.model.Constants.PERMISSION_REQUEST_CODE import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_CARD import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_FINGERPRINT import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_KEY import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_LOCK 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.model.bo.WorkTicketGetBO import com.grkj.iscs.model.bo.WorkTicketSendBO import com.grkj.iscs.model.vo.ticket.LockPointUpdateReqVO import com.grkj.iscs.model.vo.ticket.TicketDetailRespVO import com.grkj.iscs.presentation.PresentationManager import com.grkj.iscs.util.ActivityUtils import com.grkj.iscs.util.CommonUtils import com.grkj.iscs.util.Executor import com.grkj.iscs.util.NetApi import com.grkj.iscs.util.SPUtils import com.grkj.iscs.util.ToastUtils import com.grkj.iscs.util.log.LogUtil import pub.devrel.easypermissions.AfterPermissionGranted /** * 业务层管理 */ object BusinessManager { var NEED_AUTH = true // 归还设备是否需要登录及角色验证 private var CAN_RETURN = true get() { // TODO 临时注掉,方便调试 val loginUser = SPUtils.getLoginUser(MyApplication.instance!!.applicationContext!!) return (NEED_AUTH && loginUser != null) || !NEED_AUTH } /****************************************** ModBus ******************************************/ fun connectDock(isNeedInit: Boolean = false) { // 暂定100上限 // TODO demo为了快用3个 ModBusController.setSlaveCount(3) ModBusController.interruptReadTrashBinStatus(false) ModBusController.start(MyApplication.instance!!.applicationContext) // ModBusController.unregisterListener(MyApplication.instance!!.applicationContext) if (isNeedInit) { ModBusController.initDevicesStatus() } } fun disconnectDock() { ModBusController.stop() } class DeviceListener( val key: Any, val callBack: (DockBean) -> Unit ) private val listeners = ArrayList() fun registerStatusListener(key: Any, listener: (DockBean) -> Unit) { listeners.add(DeviceListener(key, listener)) } fun unregisterListener(key: Any) { val it = listeners.iterator() while (it.hasNext()) { if (it.next().key == key) { it.remove() } } } /** * 总的监听,做预处理,其余的所有监听均使用本监听处理后的数据,只允许调用一次 */ fun registerMainListener() { ModBusController.registerStatusListener(this) { res -> LogUtil.i("设备状态:${(res as List).map { it.toHexStrings() }}") res.forEach { bytes -> val dockBean = ModBusController.updateStatus(bytes) ?: return@forEach // if (!CAN_RETURN) { // return@forEach // } when (dockBean.type) { DOCK_TYPE_KEY -> { dockBean.deviceList.forEach { keyBean -> if (keyBean.isExist) { // 放回钥匙,读取rfid ModBusController.readKeyRfid(dockBean.addr.toInt() - 1, if ((keyBean as DockBean.KeyBean).isLeft) 0 else 1) { isLeft, res -> val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros() ModBusController.updateKeyRfid(dockBean.addr.toInt(), keyBean.isLeft, rfid) if (PresentationManager.mConfigKeyList.any { it.rfid == rfid }) { val mac = PresentationManager.mConfigKeyList.find { it.rfid == rfid }?.keyMac ModBusController.updateKeyMac(dockBean.addr.toInt(), keyBean.isLeft, mac!!) } // NetApi.getKeyInfo(rfid) { // if (it != null && !it.macAddress.isNullOrEmpty()) { // ModBusController.updateKeyMac(dockBean.addr.toInt(), keyBean.isLeft, it.macAddress) // showKeyReturnDialog(it.macAddress, isLeft, dockBean.addr.toInt()) // } else { // ToastUtils.tip(R.string.get_key_info_fail) // } // } // TODO 蓝牙通信 } // ModBusController.controlKeyBuckle(false, isLeft = true, dockBean.addr.toInt() - 1) } } } DOCK_TYPE_LOCK -> { dockBean.deviceList.forEach { lockBean -> if (lockBean.isExist) { ModBusController.readLockRfid(dockBean.addr.toInt() - 1, lockBean.idx) { res -> val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros() ModBusController.updateLockRfid(dockBean.addr.toInt(), lockBean.idx, rfid) // NetApi.getLockInfo(rfid) { // if (it != null) { // TODO 考虑快速拿取 ModBusController.controlLockBuckle(false, dockBean.addr.toInt() - 1, lockBean.idx) { itRst -> if (itRst.isNotEmpty()) { // 上报锁具信息 // NetApi.updateLockReturn(rfid, MyApplication.instance!!.serialNo()) {} } } // } // } } } } } DOCK_TYPE_ELEC_LOCK_BOARD -> { // TODO 占位 } DOCK_TYPE_PORTABLE -> { // TODO 便携式待完善 dockBean.deviceList.forEach { deviceBean -> if (deviceBean.isExist) { when (deviceBean.type) { DEVICE_TYPE_KEY -> { ModBusController.readKeyRfid(dockBean.addr.toInt() - 1, deviceBean.idx) { isLeft, res -> val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros() ModBusController.updateKeyRfid(dockBean.addr.toInt(), true, rfid) NetApi.getKeyInfo(rfid) { if (it != null && !it.macAddress.isNullOrEmpty()) { ModBusController.updateKeyMac(dockBean.addr.toInt(), isLeft, it.macAddress) showKeyReturnDialog(it.macAddress, isLeft, dockBean.addr.toInt()) } else { ToastUtils.tip(R.string.get_key_info_fail) } } // TODO 蓝牙通信 } // ModBusController.controlKeyBuckle(false, isLeft = true, dockBean.addr.toInt() - 1) } DEVICE_TYPE_LOCK -> { ModBusController.readLockRfid(dockBean.addr.toInt() - 1, deviceBean.idx) { res -> val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros() ModBusController.updateLockRfid(dockBean.addr.toInt(), deviceBean.idx, rfid) NetApi.getLockInfo(rfid) { if (it != null) { // TODO 考虑快速拿取 ModBusController.controlLockBuckle(false, dockBean.addr.toInt() - 1, deviceBean.idx) { itRst -> if (itRst.isNotEmpty()) { // 上报锁具信息 NetApi.updateLockReturn(rfid, MyApplication.instance!!.serialNo()) {} } } } } } } DEVICE_TYPE_CARD -> { ModBusController.readPortalCaseCardRfid(dockBean.addr.toInt() - 1) { res -> val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros() println("卡片RFID : $rfid") } } DEVICE_TYPE_FINGERPRINT -> { } } } } } } Executor.delayOnMain(200) { listeners.forEach { it.callBack(dockBean) } } } } } /** * 钥匙归还提示确认弹框 */ private fun showKeyReturnDialog(mac: String, isLeft: Boolean, slaveIdx: Int) { val dlg = TipDialog(MyApplication.instance!!.applicationContext) dlg.setTip(MyApplication.instance!!.getString(R.string.key_return_tip)) dlg.setType(TipDialog.TYPE_CONFIRM) dlg.setConfirmListener { ModBusController.controlKeyBuckle(false, isLeft, slaveIdx) getTicketStatusBusiness(mac, ActivityUtils.currentActivity() as BaseActivity<*>) { b, s, rst -> (ActivityUtils.currentActivity() as BaseActivity<*>).handleLoading(b, s) } } } fun readLockBuckleStatus() { // TODO slaveIdx暂时写死,调试用 ModBusController.readBuckleStatus(true, 0) { type, res -> LogUtil.i("单slave卡扣状态 : $type - ${res.toHexStrings()}") when (type) { 0 -> { val isLeftLock = (res[4].toInt() shr 0) and 0x1 == 1 val isRightLock = (res[4].toInt() shr 4) and 0x1 == 1 println("锁具底座卡扣状态 : $isLeftLock - $isRightLock") } 1 -> { val tempList = mutableListOf() for (i in 0..7) { tempList.add((res[4].toInt() shr i) and 0x1 == 1) } println("锁具底座卡扣1-8状态 : $tempList") } 2 -> { val lock9Status = (res[4].toInt() shr 0) and 0x1 == 1 val lock10Status = (res[4].toInt() shr 1) and 0x1 == 1 println("锁具底座卡扣9、10状态 : $lock9Status - $lock10Status") } } } } fun readKeyBuckleStatus() { // TODO slaveIdx暂时写死,调试用 ModBusController.readBuckleStatus(false, 1) { type, res -> LogUtil.i("单slave卡扣状态 : $type - ${res.toHexStrings()}") // TODO 待验证 when (type) { 0 -> { val isLeftLock = (res[4].toInt() shr 0) and 0x1 == 1 val isRightLock = (res[4].toInt() shr 4) and 0x1 == 1 println("钥匙底座卡扣状态 : $isLeftLock - $isRightLock") } 1 -> { val tempList = mutableListOf() for (i in 0..7) { tempList.add((res[4].toInt() shr i) and 0x1 == 1) } println("锁具底座卡扣1-8状态 : $tempList") } 2 -> { val lock9Status = (res[4].toInt() shr 0) and 0x1 == 1 val lock10Status = (res[4].toInt() shr 1) and 0x1 == 1 println("锁具底座卡扣9、10状态 : $lock9Status - $lock10Status") } } } } /** * 检查钥匙和锁具数量 * * @param needLockCount 需要的锁具的数量(可能在别的机柜取过) */ fun checkEquipCount(needLockCount: Int, callBack: (Pair?, MutableMap>) -> Unit) { var lockCount = 0 val lockMap = ModBusController.getLocks(needLockCount) lockMap.forEach { (_, rfidList) -> lockCount += rfidList.size } val key = ModBusController.getOneKey() var tipStr = "" println("checkEquipCount : $lockCount - $needLockCount") if (lockCount < needLockCount) { val msg = MyApplication.instance!!.applicationContext.resources.getString(R.string.lock_is_not_enough) LogUtil.w(msg) tipStr = msg } if (key == null) { val msg = MyApplication.instance!!.applicationContext.resources.getString(R.string.key_is_not_enough) LogUtil.w(msg) tipStr = if (tipStr.isEmpty()) { msg } else { tipStr + "\n" + msg } } if (tipStr.isNotEmpty()) { ToastUtils.tip(tipStr) } callBack.invoke(if (lockCount < needLockCount) null else key, lockMap) } /****************************************** 蓝牙 ******************************************/ /******************************************蓝牙通用准备******************************************/ fun prepareBle( mac: String, activity: AppCompatActivity, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?, prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)? ) { Executor.runOnMain { CommonUtils.checkBlePermission(activity) { doScanBle(mac, loadingCallBack, prepareDoneCallBack) } } } @AfterPermissionGranted(PERMISSION_REQUEST_CODE) fun doScanBle(mac: String, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?, prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?) { LogUtil.d("扫描开始:$mac") loadingCallBack?.invoke(true, MyApplication.instance?.getString(R.string.start_scanning_for_devices), null) BleUtil.instance?.scan(object : CustomBleScanCallback() { override fun onPrompt(promptStr: String?) { BleManager.getInstance().enableBluetooth() } override fun onScanStarted(success: Boolean) { LogUtil.d("扫描开始:${success}") // BleUtil.instance?.deviceList?.clear() } override fun onScanning(bleDevice: BleDevice?) { bleDevice?.let { Log.d("doScanBle", "扫描到的设备:${it.mac}") if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (!it.name.isNullOrBlank()) { // BleUtil.instance?.deviceList?.add(BleBean(it)) } else { } } else { // BleUtil.instance?.deviceList?.add(BleBean(it)) } } } override fun onScanFinished(scanResultList: MutableList?) { loadingCallBack?.invoke(false, null, null) // if (BleUtil.instance?.deviceList?.isEmpty() == true) { // ToastUtils.tip(R.string.ble_no_device_found) // loadingCallBack?.invoke(false, null, false) // return // } // BleUtil.instance?.getBleDeviceByMac(mac)?.bleDevice?.let { // doConnect(it, loadingCallBack, prepareDoneCallBack) // } scanResultList?.find { it.mac == mac }?.let { doConnect(it, loadingCallBack, prepareDoneCallBack) } } }) } /** * 连接蓝牙设备 */ fun doConnect( bleDevice: BleDevice, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?, prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)? ) { loadingCallBack?.invoke(true, CommonUtils.getStr(R.string.ble_connecting), null) BleManager.getInstance().disconnect(bleDevice) BleUtil.instance?.connectBySelect(bleDevice, object : CustomBleGattCallback() { override fun onPrompt(promptStr: String?) { loadingCallBack?.invoke(false, promptStr, false) } override fun onStartConnect() {} override fun onConnectFail(bleDevice: BleDevice?, exception: BleException?) { loadingCallBack?.invoke(false, CommonUtils.getStr(R.string.ble_connect_fail), false) prepareDoneCallBack?.invoke(false, null) } override fun onConnectSuccess(bleDevice: BleDevice?, gatt: BluetoothGatt?, status: Int) { loadingCallBack?.invoke(false, null, null) LogUtil.i("onConnectSuccess : $bleDevice") bleDevice?.let { val bleBean = BleBean(it) ToastUtils.tip(R.string.connect_success) BleUtil.instance?.deviceList?.add(bleBean) // 设置MTU Executor.delayOnMain(200) { BleUtil.instance?.setMtu(it) } // 监听 Executor.delayOnMain(500) { indicate(bleBean, loadingCallBack, prepareDoneCallBack) } } } override fun onDisConnected(isActiveDisConnected: Boolean, device: BleDevice?, gatt: BluetoothGatt?, status: Int) { loadingCallBack?.invoke(false, null, false) ToastUtils.tip(CommonUtils.getStr(R.string.ble_disconnect)) BleUtil.instance?.getBleDeviceByMac(device?.mac)?.let { BleUtil.instance?.deviceList?.remove(it) } } }) } /** * 监听蓝牙设备 */ private fun indicate( bleBean: BleBean?, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?, prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)? ) { loadingCallBack?.invoke(true, MyApplication.instance?.getString(R.string.start_indicating), null) bleBean?.let { BleUtil.instance?.indicate(it.bleDevice, indicateCallback = object : CustomBleIndicateCallback() { override fun onPrompt(promptStr: String?) { LogUtil.i("监听onPrompt : $promptStr") } override fun onConnectPrompt(promptStr: String?) { LogUtil.i("监听onConnectPrompt : $promptStr") } override fun onDisConnectPrompt(promptStr: String?) { LogUtil.i("监听onDisConnectPrompt : $promptStr") } override fun onIndicateSuccess() { LogUtil.i("监听成功") // 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\"}]}" // sendTicket(testStr, it.bleDevice, loadingCallBack) getToken(bleBean, loadingCallBack, prepareDoneCallBack) } override fun onIndicateFailure(exception: BleException?) { loadingCallBack?.invoke(false, null, false) ToastUtils.tip(MyApplication.instance?.getString(R.string.indicate_fail)) LogUtil.i("监听失败") prepareDoneCallBack?.invoke(false, null) } override fun onCharacteristicChanged(data: ByteArray?) { LogUtil.i("监听数据 : ${data?.toHexStrings()}") data?.let { itData -> handleRsp(it, itData, loadingCallBack) } } }) } } /** * 获取蓝牙钥匙token */ private fun getToken( bleBean: BleBean?, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?, prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)? ) { loadingCallBack?.invoke(true, MyApplication.instance?.getString(R.string.start_getting_token), null) bleBean?.let { BleCmdManager.getToken(it.bleDevice.mac, object : CustomBleWriteCallback() { override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) { loadingCallBack?.invoke(false, MyApplication.instance?.getString(R.string.get_token_success), null) LogUtil.i("getToken success : ${bleBean.bleDevice.mac}") prepareDoneCallBack?.invoke(true, bleBean) } override fun onWriteFailure(exception: BleException?) { loadingCallBack?.invoke(false, MyApplication.instance?.getString(R.string.get_token_fail), false) LogUtil.e("getToken fail : ${bleBean.bleDevice.mac}") prepareDoneCallBack?.invoke(false, null) } }) } } /******************************************蓝牙通用准备结束******************************************/ /** * 下发工作票 * TODO 演示demo专用 * @param loadingCallBack 是否显示loading、提示信息、是否结束(true成功结束、false失败结束、null继续执行) */ fun sendTicketBusiness( mac: String, activity: AppCompatActivity, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)? ) { // prepareBle(mac, activity, loadingCallBack) { done, bleBean -> // if (done) { // Executor.delayOnMain(500) { // TODO 蓝牙准备操作 val bleBean = BleUtil.instance?.getBleDeviceByMac(mac) if (bleBean == null) { ToastUtils.tip(R.string.simple_key_is_not_connected) return } // 单bleBean json赋值 bleBean?.ticketSend = PresentationManager.getSimpleTicketJson() bleBean?.ticketSend?.let { itJson -> sendTicket(itJson, bleBean.bleDevice, loadingCallBack) } // } // } else { // loadingCallBack?.invoke(false, null, false) // } // } } /** * 下发工作票 */ fun sendTicketBusiness( mac: String, ticketDetail: TicketDetailRespVO, activity: AppCompatActivity, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?, ) { prepareBle(mac, activity, loadingCallBack) { done, bleBean -> if (done) { Executor.delayOnMain(500) { // 单bleBean json赋值 bleBean?.ticketSend = generateTicketSendJson(ticketDetail) bleBean?.ticketSend?.let { itJson -> sendTicket(itJson, bleBean.bleDevice, loadingCallBack) } } } else { loadingCallBack?.invoke(false, null, false) } } } /** * 读取工作票完成情况 */ fun getTicketStatusBusiness(mac: String, activity: AppCompatActivity, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) { prepareBle(mac, activity, loadingCallBack) { done, bleBean -> if (done) { Executor.delayOnMain(500) { // // TODO 蓝牙准备操作 // val bleBean = BleUtil.instance?.getBleDeviceByMac(mac) // if (bleBean == null) { // ToastUtils.tip(R.string.simple_key_is_not_connected) // return // } getTicketStatus(bleBean!!.bleDevice, loadingCallBack) } } else { loadingCallBack?.invoke(false, null, false) } } } private fun sendTicket(jsonStr: String, bleDevice: BleDevice, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) { val ctx = MyApplication.instance!! loadingCallBack?.invoke(true, ctx.getString(R.string.simple_start_send_ticket), null) BleCmdManager.sendWorkTicket(jsonStr, bleDevice = bleDevice, callback = object : CustomBleWriteCallback() { override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) { println("sendTicket success") loadingCallBack?.invoke(true, ctx.getString(R.string.simple_sending_ticket), null) } override fun onWriteFailure(exception: BleException?) { LogUtil.e("sendTicket fail : ${bleDevice.mac}") loadingCallBack?.invoke(false, ctx.getString(R.string.simple_send_ticket_fail), null) } }) } /** * 生成下发工作票Json * * @param vo 工作票详情 */ private fun generateTicketSendJson(vo: TicketDetailRespVO): String { // 用ticketStatus的"待上锁"进行判断 val isLock = vo.ticketStatus == Constants.TICKET_STATUS_READY_TO_LOCK val bo = WorkTicketSendBO( cardNo = SPUtils.getLoginUser(MyApplication.instance!!.applicationContext)?.cardNfc, ) CommonUtils.getDiffHours(vo.ticketEndTime)?.let { bo.effectiveTime = it } val dataBO = WorkTicketSendBO.DataBO( taskCode = vo.ticketCode, taskId = vo.ticketId.toString(), codeId = 1 ) val taskList = ArrayList() vo.pointDetailVOList?.let { itList -> itList.forEach { pointVO -> val task = WorkTicketSendBO.DataBO.DataListBO( dataId = pointVO.pointId?.toInt(), equipRfidNo = pointVO.pointNfc, infoRfidNo = pointVO.pointName, target = if (isLock) 0 else 1 ) pointVO.prePointId?.let { task.prevId = it.toInt() } if (!isLock) { task.infoRfidNo = pointVO.lockId.toString() } // TODO partCode待补充 taskList.add(task) } } dataBO.dataList = taskList bo.data = mutableListOf(dataBO) if (isLock) { bo.lockList = mutableListOf() } // TODO partList 待补充 val jsonStr = Gson().toJson(bo) return jsonStr } fun handleRsp(bleBean: BleBean, byteArray: ByteArray, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) { // TODO Token校验 // val len = byteArray[2].toInt() // val token = byteArray.copyOfRange(len + 7, len + 11) // if (token.contentEquals(bleBean.token)) { // LogUtil.i("Token is right") // } else { // LogUtil.e("Token is wrong") // } when { // 获取令牌 byteArray.startsWith(BleConst.RSP_GET_TOKEN) -> handleToken(bleBean.bleDevice, byteArray) // 工作模式切换 byteArray.startsWith(BleConst.RSP_SWITCH_MODE) -> handleSwitchModeResult(byteArray, loadingCallBack) // 工作票下发 byteArray.startsWith(BleConst.RSP_SEND_WORK_TICKET) -> handleWorkTicketResult(bleBean, byteArray, loadingCallBack) // 获取设备工作票完成情况 byteArray.startsWith(BleConst.RSP_WORK_TICKET_RESULT) && byteArray[3] == 0x02.toByte() -> handleTicketStatus(bleBean.bleDevice, byteArray, loadingCallBack) } } /** * 令牌处理 */ private fun handleToken(bleDevice: BleDevice, byteArray: ByteArray) { LogUtil.i("handleToken : ${byteArray.toHexStrings()}") BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let { it.token = byteArrayOf(byteArray[11], byteArray[12], byteArray[13], byteArray[14]) println("Token 赋值 ${it.token?.toHexStrings()} : ${bleDevice.mac}") } } /** * 工作模式切换结果 * job : 0x01:工作模式 0x02:待机模式 * res : 0x01:成功 0x02:失败 */ private fun handleSwitchModeResult(byteArray: ByteArray, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) { LogUtil.i("handleSwitchModeResult : ${byteArray.toHexStrings()}") val ctx = MyApplication.instance!! val job = byteArray[4] val res = byteArray[5] loadingCallBack?.invoke(false, null, null) if (res == 0x01.toByte() && job == 0x01.toByte()) { loadingCallBack?.invoke(false, ctx.getString(R.string.simple_switch_work_mode_success), null) // TODO 切成工作模式断开,待机模式不断开 BleManager.getInstance().disconnectAllDevice() } else if (res == 0x02.toByte() && job == 0x01.toByte()) { loadingCallBack?.invoke(false, ctx.getString(R.string.simple_switch_standby_mode_success), null) } } /** * 工作票下发结果 * res:0x00:成功 0x01:失败 0x02:传输超时 0x0D:当前IDX超出范围 0x0E:当前数据CRC校验失败 0x14:JSON结构错误 0x63:未知错误 */ private fun handleWorkTicketResult(bleBean: BleBean, byteArray: ByteArray, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) { val ctx = MyApplication.instance!! LogUtil.i("handleWorkTicketResult : ${byteArray.toHexStrings()}") loadingCallBack?.invoke(false, null, null) val idx = byteArray[4] + byteArray[5] val total = byteArray[6] + byteArray[7] val res = byteArray[8] if (idx != total - 1) { if ((res == 0x00.toByte() || res == 0x02.toByte())) { // TODO 要判断res BleCmdManager.sendWorkTicket( BleUtil.instance?.getBleDeviceByMac(bleBean.bleDevice.mac)?.ticketSend!!, if (res == 0x00.toByte()) idx + 1 else idx, bleBean.bleDevice, object : CustomBleWriteCallback() { override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {} override fun onWriteFailure(exception: BleException?) {} }) } } else { LogUtil.i("Work ticket is done") // 下发完毕,切换工作模式 loadingCallBack?.invoke(true, ctx.getString(R.string.simple_switch_work_mode), null) BleCmdManager.switchMode(STATUS_WORK, bleBean.bleDevice, object : CustomBleWriteCallback() { override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) { println("switch mode 1 success")} override fun onWriteFailure(exception: BleException?) { println("switch mode 1 fail")} }) // 打开钥匙卡扣 val keyBean = ModBusController.getKeyByMac(bleBean.bleDevice.mac) if (keyBean == null) { loadingCallBack?.invoke(false, ctx.getString(R.string.simple_key_not_found), false) ToastUtils.tip(R.string.simple_key_not_exists) } else { loadingCallBack?.invoke(false, null, true) val dock = ModBusController.getDockByKeyMac(bleBean.bleDevice.mac) ModBusController.controlKeyBuckle(true, keyBean.isLeft, dock?.addr!!.toInt() - 1) } } } /** * 处理工作票完成情况 */ private fun handleTicketStatus(bleDevice: BleDevice, byteArray: ByteArray, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) { // TODO 需要有超时重传机制 LogUtil.i("handleTicketStatus : ${byteArray.toHexStrings()}") val ctx = MyApplication.instance!! val total = byteArray[4] + byteArray[5] val idx = byteArray[6] + byteArray[7] val crc = byteArray[8] + byteArray[9] val size = byteArray[10].toUByte() + byteArray[11].toUByte() println("工作票数据 : $total : $idx : $size") // 数据组装 BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let { it.ticketStatus += byteArray.copyOfRange(12, 12 + size.toInt()) } // TODO 缺少res处理 if (idx != total - 1) { loadingCallBack?.invoke(true, ctx.getString(R.string.simple_get_ticket_part), null) getTicketStatusPart((idx + 1).toByteArray(), total.toByteArray(), byteArrayOf(0x01.toByte()), bleDevice, object : CustomBleWriteCallback() { override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) { println("getTicketStatusPart success") } override fun onWriteFailure(exception: BleException?) { println("getTicketStatusPart fail") } }) } else { loadingCallBack?.invoke(false, ctx.getString(R.string.simple_get_ticket_status_done), null) BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let { println("工作票完成接收 : ${String(it.ticketStatus)}") // TD:Ticket Done loadingCallBack?.invoke(false, "TD${String(it.ticketStatus)}", true) // TODO 清空ticket it.ticketStatus = byteArrayOf() // TODO 根据工作票完成情况,切换为待机模式 BleCmdManager.switchMode(STATUS_READY, bleDevice, object : CustomBleWriteCallback() { override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) { println("switch mode 1 success")} override fun onWriteFailure(exception: BleException?) { println("switch mode 1 fail")} }) val dock = ModBusController.getDockByKeyMac(bleDevice.mac) val keyBean = dock?.getKeyList()?.find { it.mac == bleDevice.mac } keyBean?.let { ModBusController.controlKeyBuckle(false, keyBean.isLeft, dock.addr.toInt() - 1) } // 上报隔离点状态 val workTicketGetBO = Gson().fromJson(String(it.ticketStatus), WorkTicketGetBO::class.java) val keyNfc = ModBusController.getKeyByMac(bleDevice.mac)?.rfid workTicketGetBO?.data?.forEach { data -> val updateList = mutableListOf() data.dataList?.forEach { dataListDTO -> val updateVO = LockPointUpdateReqVO( data.taskId?.toLong(), dataListDTO.infoRfidNo, dataListDTO.equipRfidNo, keyNfc!!, dataListDTO.target, dataListDTO.status ) updateList.add(updateVO) } // 上报点位钥匙绑定 // NetApi.updateLockPointBatch(updateList) { itRst -> // // TODO 上报结果 // } // 上报钥匙归还 // NetApi.updateKeyReturn(data.taskId?.toLong()!!, keyNfc!!, MyApplication.instance!!.serialNo()) { // // } } } } } /** * 获取工作票完成情况分包 */ private fun getTicketStatusPart(idx: ByteArray, total: ByteArray, res: ByteArray, bleDevice: BleDevice, callback: CustomBleWriteCallback?) { BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let { BleUtil.instance?.write(it.bleDevice, cmd = BleCmdManager.assembleData(it, REQ_WORK_TICKET_RESULT_PART + idx + total + res), writeCallback = callback) } } /** * 获取工作票完成情况 */ private fun getTicketStatus(bleDevice: BleDevice, loadingCallBack: ((Boolean, String?, Boolean?) -> Unit)?) { loadingCallBack?.invoke(true, MyApplication.instance?.getString(R.string.start_getting_ticket), null) BleCmdManager.getTicketStatus(bleDevice, object : CustomBleWriteCallback() { override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) { loadingCallBack?.invoke(false, MyApplication.instance?.getString(R.string.get_ticket_success), null) println("getTicketStatus success")} override fun onWriteFailure(exception: BleException?) { loadingCallBack?.invoke(false, MyApplication.instance?.getString(R.string.get_ticket_fail), false) println("getTicketStatus fail")} }) } }