| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- package com.grkj.iscs.ble
- import com.clj.fastble.data.BleDevice
- import com.clj.fastble.exception.BleException
- import com.grkj.iscs.extentions.crc16
- import com.grkj.iscs.extentions.startsWith
- import com.grkj.iscs.extentions.toByteArray
- import com.grkj.iscs.extentions.toHexStrings
- import com.grkj.iscs.ble.BleConst.REQ_CURRENT_STATUS
- import com.grkj.iscs.ble.BleConst.REQ_GET_TOKEN
- import com.grkj.iscs.ble.BleConst.REQ_GET_VERSION
- import com.grkj.iscs.ble.BleConst.REQ_POWER_STATUS
- import com.grkj.iscs.ble.BleConst.REQ_SEND_WORK_TICKET
- import com.grkj.iscs.ble.BleConst.REQ_SWITCH_MODE
- import com.grkj.iscs.ble.BleConst.REQ_TRANSFER_FILE
- import com.grkj.iscs.ble.BleConst.REQ_WORK_TICKET_RESULT
- import com.grkj.iscs.ble.BleConst.REQ_WORK_TICKET_RESULT_PART
- import com.grkj.iscs.ble.BleConst.WRITE_UUID
- import com.grkj.iscs.util.Executor
- import com.grkj.iscs.util.log.LogUtil
- import java.io.File
- /**
- * 指令操作类
- */
- object BleCmdManager {
- /**
- * 拼接时间戳
- */
- private fun assembleTimeStamp(byteArray: ByteArray): ByteArray {
- return byteArray + getTimeStamp()
- }
- /**
- * 拼接时间戳 + token
- */
- private fun assembleData(bleBean: BleBean, byteArray: ByteArray): ByteArray? {
- bleBean.token?.let {
- return assembleTimeStamp(byteArray) + it
- } ?: run {
- // TODO 有问题,一直循环
- // getToken(bleBean.bleDevice.mac, object : CustomBleWriteCallback() {
- // override fun onPrompt(promptStr: String?) {}
- //
- // override fun onConnectPrompt(promptStr: String?) {}
- //
- // override fun onDisConnectPrompt(promptStr: String?) {}
- //
- // override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {}
- //
- // override fun onWriteFailure(exception: BleException?) {}
- //
- // })
- // // TODO 临时方案
- // Thread.sleep(100)
- // return assembleData(bleBean, byteArray)
- return null
- }
- }
- private fun getTimeStamp(): ByteArray {
- val tempArr = (System.currentTimeMillis() / 1000).toByteArray()
- val timeStampArr = byteArrayOf(tempArr[0], tempArr[1], tempArr[2], tempArr[3])
- return timeStampArr
- }
- fun handleRsp(bleBean: BleBean, byteArray: ByteArray) {
- 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)
- // 工作票下发
- byteArray.startsWith(BleConst.RSP_SEND_WORK_TICKET) -> handleWorkTicketResult(bleBean, byteArray)
- // 获取设备当前状态
- byteArray.startsWith(BleConst.RSP_CURRENT_STATUS) -> handleCurrentStatus(byteArray)
- // 获取钥匙电量
- byteArray.startsWith(BleConst.RSP_POWER_STATUS) -> handlePowerStatus(byteArray)
- // 传输文件
- byteArray.startsWith(BleConst.RSP_TRANSFER_FILE) && byteArray[3] == 0x01.toByte() -> handleFileRsp(bleBean, byteArray)
- // 获取固件版本号
- byteArray.startsWith(BleConst.RSP_GET_VERSION) -> handleVersion(byteArray)
- // 获取设备工作票完成情况
- byteArray.startsWith(BleConst.RSP_WORK_TICKET_RESULT) && byteArray[3] == 0x02.toByte() ->
- handleTicketStatus(bleBean.bleDevice, byteArray)
- }
- }
- /**
- * 获取令牌
- */
- fun getToken(mac: String?, callback: CustomBleWriteCallback?) {
- LogUtil.i("$mac")
- BleUtil.instance?.getBleDeviceByMac(mac)?.bleDevice?.let {
- LogUtil.i("Get token : $mac")
- BleUtil.instance?.write(it, cmd = assembleTimeStamp(REQ_GET_TOKEN), writeCallback = callback)
- }
- }
- /**
- * 令牌处理
- */
- 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}")
- }
- }
- /**
- * 工作模式切换
- *
- * @param mode 0x01:工作模式 0x02:待机模式
- */
- fun switchMode(mode: ByteArray, bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
- BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let {
- BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_SWITCH_MODE + mode), writeCallback = callback)
- }
- }
- /**
- * 工作模式切换结果
- * job : 0x01:工作模式 0x02:待机模式
- * res : 0x01:成功 0x02:失败
- */
- private fun handleSwitchModeResult(byteArray: ByteArray) {
- LogUtil.i("handleSwitchModeResult : ${byteArray.toHexStrings()}")
- val job = byteArray[4]
- val res = byteArray[5]
- }
- /**
- * 工作票下发
- */
- fun sendWorkTicket(json: String, idx: Int = 0, bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
- LogUtil.i("sendWorkTicket : $idx")
- BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let {
- it.ticketSend = json
- }
- val totalLength = json.toByteArray().size
- val totalPackets = (totalLength + 128 - 1) / 128
- val total = totalPackets.toByteArray()
- val data = if (idx == totalPackets - 1) {
- json.toByteArray().copyOfRange(idx * 128, json.toByteArray().size - 1)
- } else {
- json.toByteArray().copyOfRange(idx * 128, (idx + 1) * 128)
- }
- // val jsonInfo = total + idx.toByteArray() + CRC16.crc16(data, 0, data.size - 1).toByteArray() + data.size.toByteArray() + data
- val jsonInfo = total + idx.toByteArray() + data.crc16(0, data.size) + data.size.toByteArray() + data
- println("xixi1 : ${total.size} : ${idx.toByteArray().size} : ${data.crc16(0, data.size).size} : ${data.size.toByteArray().size} : ${data.size}")
- println("xixi2 : ${(jsonInfo.size + 1).toByteArray(1).size} : ${0x02.toByteArray(1).size} : ${jsonInfo.size}")
- val cmd = REQ_SEND_WORK_TICKET + (jsonInfo.size + 1).toByteArray(1) + 0x02.toByteArray(1) + jsonInfo
- BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let {
- BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, cmd), writeCallback = callback)
- }
- }
- /**
- * 工作票下发结果
- * res:0x00:成功 0x01:失败 0x02:传输超时 0x0D:当前IDX超出范围 0x0E:当前数据CRC校验失败 0x14:JSON结构错误 0x63:未知错误
- */
- private fun handleWorkTicketResult(bleBean: BleBean, byteArray: ByteArray) {
- LogUtil.i("handleWorkTicketResult : ${byteArray.toHexStrings()}")
- val idx = byteArray[4] + byteArray[5]
- val total = byteArray[6] + byteArray[7]
- val res = byteArray[8]
- if (idx != total - 1 && (res == 0x00.toByte() || res == 0x02.toByte())) {
- // TODO 要判断res
- sendWorkTicket(
- BleUtil.instance?.getBleDeviceByMac(bleBean.bleDevice.mac)?.ticketSend!!,
- if (res == 0x00.toByte()) idx + 1 else idx,
- bleBean.bleDevice,
- object : CustomBleWriteCallback() {
- override fun onPrompt(promptStr: String?) {}
- override fun onConnectPrompt(promptStr: String?) {}
- override fun onDisConnectPrompt(promptStr: String?) {}
- override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {}
- override fun onWriteFailure(exception: BleException?) {}
- })
- }
- }
- /**
- * 获取设备当前状态
- */
- fun getCurrentStatus(bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
- BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let {
- BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_CURRENT_STATUS), writeCallback = callback)
- }
- }
- /**
- * 处理设备当前状态
- * 0x01:工作模式 0x02:待机模式 0x03:故障状态
- */
- private fun handleCurrentStatus(byteArray: ByteArray) {
- LogUtil.i("handleCurrentStatus : ${byteArray.toHexStrings()}")
- val job = byteArray[4]
- }
- /**
- * 获取工作票完成情况
- */
- fun getTicketStatus(bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
- BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let {
- BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_WORK_TICKET_RESULT), writeCallback = callback)
- }
- }
- /**
- * 处理工作票完成情况
- */
- private fun handleTicketStatus(bleDevice: BleDevice, byteArray: ByteArray) {
- // TODO 需要有超时重传机制
- LogUtil.i("handleTicketStatus : ${byteArray.toHexStrings()}")
- 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) {
- getTicketStatusPart((idx + 1).toByteArray(), total.toByteArray(), byteArrayOf(0x01.toByte()), bleDevice, object : CustomBleWriteCallback() {
- override fun onPrompt(promptStr: String?) {}
- override fun onConnectPrompt(promptStr: String?) {}
- override fun onDisConnectPrompt(promptStr: String?) {}
- override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
- println("getTicketStatusPart success")
- }
- override fun onWriteFailure(exception: BleException?) {
- println("getTicketStatusPart fail")
- }
- })
- } else {
- BleUtil.instance?.getBleDeviceByMac(bleDevice.mac)?.let {
- println("工作票完成接收 : ${String(it.ticketStatus)}")
- // TODO 清空ticket
- // it.ticket = byteArrayOf()
- }
- }
- }
- /**
- * 获取工作票完成情况分包
- */
- 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 = assembleData(it, REQ_WORK_TICKET_RESULT_PART + idx + total + res), writeCallback = callback)
- }
- }
- /**
- * 获取钥匙电量
- */
- fun getPower(mac: String?, callback: CustomBleWriteCallback?) {
- BleUtil.instance?.getBleDeviceByMac(mac)?.let {
- BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_POWER_STATUS), writeCallback = callback)
- }
- }
- /**
- * 处理钥匙电量
- * bat:电量百分比,范围 0-100,单位:%
- * chg:0x01:未充电 0x02:充电中 0x03:充满
- */
- private fun handlePowerStatus(byteArray: ByteArray) {
- LogUtil.i("handlePowerStatus : ${byteArray.toHexStrings()}")
- val bat = byteArray[4].toInt()
- val chg = byteArray[5]
- }
- /**
- * 发送文件
- * type: 1:固件文件 2:点位PNG文件
- * FLNM:文件名(不含扩展名)
- * FLSZ:文件大小(字节)
- * FLCRC:文件的CRC-16
- * PGTOTAL:文件总包数
- * PGIDX:当前包idx
- * PGCRC:当前包CRC-16
- * PGSZ:当前包长度(字节)
- * PGDATA:当前包数据
- */
- fun sendFile(type: Int, file: File, idx: Int = 0, mac: String?, callback: CustomBleWriteCallback?) {
- Executor.runOnIO {
- LogUtil.i("sendFile : $idx")
- BleUtil.instance?.getBleDeviceByMac(mac)?.let {
- it.fileSend = file
- }
- val pgtotal = (file.readBytes().size + 128 - 1) / 128
- if (idx == pgtotal) {
- LogUtil.i("Send finish")
- return@runOnIO
- }
- val flnm = file.name.substringBeforeLast(".").toByteArray(8)
- val flsz = file.readBytes().size.toByteArray(4)
- val flcrc = file.readBytes().crc16()
- val pgdata = if (idx == pgtotal - 1) {
- file.readBytes().copyOfRange(idx * 128, file.readBytes().size - 1)
- } else {
- file.readBytes().copyOfRange(idx * 128, (idx + 1) * 128)
- }
- val pgsz = pgdata.size.toByteArray()
- val pgcrc = pgdata.crc16()
- val fileInfo = byteArrayOf(type.toByte()) + flnm + flsz + flcrc + pgtotal.toByteArray() + idx.toByteArray() + pgcrc + pgsz + pgdata
- // println("______________________________________________________________________________")
- // println("${file.readBytes().size}")
- // println("${byteArrayOf(type.toByte()).size} : ${flnm.size} : ${flsz.size} : ${flcrc.size} : ${pgtotal.toByteArray().size} : ${idx.toByteArray().size} : ${pgcrc.size} : ${pgsz.size} : ${pgdata.size}")
- // println("______________________________________________________________________________")
- // println("file info size : ${fileInfo.size}")
- val cmd = REQ_TRANSFER_FILE + (fileInfo.size + 1).toByteArray(1) + 0x01.toByteArray(1) + fileInfo
- // println("cmd size : ${REQ_TRANSFER_FILE.size} : ${(fileInfo.size + 1).toByteArray(1).size} : ${0x01.toByteArray(1).size} : ${fileInfo.size}")
- BleUtil.instance?.getBleDeviceByMac(mac)?.let {
- BleUtil.instance?.write(it.bleDevice, writeUUID = WRITE_UUID, cmd = assembleData(it, cmd), writeCallback = callback)
- }
- Thread.sleep(50)
- sendFile(type, file, idx + 1, mac, callback)
- }
- }
- /**
- * 处理发送分包文件响应
- * type: 0x01:固件文件 0x02:点位PNG文件
- */
- private fun handleFileRsp(bleBean: BleBean, byteArray: ByteArray) {
- LogUtil.i("handleFileRsp : ${byteArray.toHexStrings()}")
- val type = byteArray[4]
- val res = byteArray[17]
- val total = byteArray[15] + byteArray[16]
- val idx = byteArray[13] + byteArray[14]
- if (idx != total - 1 && (res == 0x00.toByte() || res == 0x02.toByte())) {
- // TODO 不用等回复再发
- // sendFile(type.toInt(),
- // BleUtil.instance?.getBleDeviceByMac(bleBean.bleDevice.mac)?.fileSend!!,
- // if (res == 0x00.toByte()) idx + 1 else idx,
- // bleBean.bleDevice.mac,
- // object : CustomBleWriteCallback() {
- // override fun onPrompt(promptStr: String?) {}
- //
- // override fun onConnectPrompt(promptStr: String?) {}
- //
- // override fun onDisConnectPrompt(promptStr: String?) {}
- //
- // override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {}
- //
- // override fun onWriteFailure(exception: BleException?) {}
- //
- // })
- }
- }
- /**
- * 获取版本
- */
- fun getVersion(mac: String?, callback: CustomBleWriteCallback?) {
- BleUtil.instance?.getBleDeviceByMac(mac)?.let {
- BleUtil.instance?.write(it.bleDevice, cmd = assembleData(it, REQ_GET_VERSION), writeCallback = callback)
- }
- }
- /**
- * 处理软件/硬件版本
- */
- private fun handleVersion(byteArray: ByteArray) {
- val sofVersion = parseVersion(byteArray[4])
- val hardVersion = parseVersion(byteArray[5])
- LogUtil.i("$sofVersion : $hardVersion")
- }
- /**
- * 版本解析
- */
- private fun parseVersion(byte: Byte): String {
- // 将 Byte 转换为 Int 以便更容易进行位操作
- val intValue = byte.toInt()
- // 提取高 4 位作为主版本号
- val majorVersion = (intValue and 0xF0) ushr 4
- // 提取低 4 位作为次版本号
- val minorVersion = intValue and 0x0F
- return "V$majorVersion.$minorVersion"
- }
- }
|