Browse Source

Merge branch 'new_dev' of https://github.com/deepcloud2048/deep_voice into new_dev

newdev_shunjiawei
tanlongsheng 11 months ago
parent
commit
a177d7507c
  1. 135
      local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift

135
local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift

@ -891,22 +891,27 @@ private var cmdReplyType: UInt8 = 0
} }
/// 处理接收到的响应数据 /// 处理接收到的响应数据
///
/// - 功能:
/// - 解析设备响应帧,校验头、长度与 CRC
/// - 与 Android 保持一致的失败判定:当长度字段与实际长度不匹配时,上报 rawData = [length, data[data.count-2]]
/// - 在 CMD_CONTROL_CODEC 分支对齐安卓对错误响应的处理逻辑
private func handleResponseData(_ data: Data) { private func handleResponseData(_ data: Data) {
guard let characteristic = writeCharacteristic, guard let characteristic = writeCharacteristic,
connectionState == BleConst.STATE_CONNECTED else { connectionState == BleConst.STATE_CONNECTED else {
os_log(" 设备未连接", log: logger, type: .error) os_log(" 设备未连接", log: logger, type: .error)
return return
} }
guard data.count >= 4 else { guard data.count >= 4 else {
os_log("响应数据格式错误:数据长度过短", log: logger, type: .error) os_log("响应数据格式错误:数据长度过短", log: logger, type: .error)
return return
} }
// 提取帧信息 // 提取帧信息
let header = data[0] let header = data[0]
let cmd = data[1] let cmd = data[1]
let length = data[2] let length = data[2]
// 检查帧头,确保是设备响应 // 检查帧头,确保是设备响应
guard header == BleConst.DEVICE_RESPONSE_HEADER else { guard header == BleConst.DEVICE_RESPONSE_HEADER else {
// 如果是设备主动上报 // 如果是设备主动上报
@ -915,35 +920,59 @@ private var cmdReplyType: UInt8 = 0
} }
return return
} }
// 记录响应详情 // 记录响应详情
var hexString = data.map { String(format: "0x%02X", $0) }.joined(separator: ", ") var hexString = data.map { String(format: "0x%02X", $0) }.joined(separator: ", ")
os_log("收到设备响应: %@", log: logger, type: .debug, hexString) os_log("收到设备响应: %@", log: logger, type: .debug, hexString)
// 检查数据长度 // 检查数据长度(与 Android 统一失败判定保持一致)
if data.count != Int(length) + 4 { // 帧头 + 命令 + 长度 + 数据 + CRC if data.count != Int(length) + 4 { // 帧头 + 命令 + 长度 + 数据 + CRC
os_log("设备响应数据长度不匹配: 期望=%d, 实际=%d", log: logger, type: .error, Int(length) + 4, data.count) os_log("设备响应数据长度不匹配: 期望=%d, 实际=%d", log: logger, type: .error, Int(length) + 4, data.count)
// 与 Android 保持一致:构造 rawData 为 [length, 倒数第二位(payload 最后一位)]
var raw: [UInt8] = []
raw.append(length)
if data.count >= 2 {
raw.append(data[data.count - 2])
}
let resultMap: [String: Any] = [
"success": true, // 与 Android 对齐(Dart 层按 rawData 判断)
"command": Int(cmd),
"rawData": Data(raw)
]
// 推进命令队列(与后续正常路径一致)
isReply = true
cmdReplyType = cmd
if !commandQueue.isEmpty {
let nextCmd = commandQueue.removeFirst()
peripheralDevice?.writeValue(nextCmd, for: characteristic, type: .withoutResponse)
}
// 上报到 Dart 层
notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap)
return return
} }
// 计算CRC校验 - 不包括最后一个字节(CRC) // 计算CRC校验 - 不包括最后一个字节(CRC)
let payload = data.prefix(data.count - 1) let payload = data.prefix(data.count - 1)
let calculatedCrc = calculateCRC8(data: payload) let calculatedCrc = calculateCRC8(data: payload)
let receivedCrc = data[data.count - 1] let receivedCrc = data[data.count - 1]
if calculatedCrc != receivedCrc { if calculatedCrc != receivedCrc {
os_log("设备响应CRC校验失败: 计算=0x%02X, 接收=0x%02X", log: logger, type: .error, calculatedCrc, receivedCrc) os_log("设备响应CRC校验失败: 计算=0x%02X, 接收=0x%02X", log: logger, type: .error, calculatedCrc, receivedCrc)
return return
} }
// 提取响应数据 // 提取响应数据
let responseData = length > 0 ? data.subdata(in: 3..<(3 + Int(length))) : Data() let responseData = length > 0 ? data.subdata(in: 3..<(3 + Int(length))) : Data()
isReply = true; isReply = true
cmdReplyType = cmd; cmdReplyType = cmd
if !commandQueue.isEmpty { if !commandQueue.isEmpty {
let nextCmd = commandQueue.removeFirst() let nextCmd = commandQueue.removeFirst()
peripheralDevice?.writeValue(nextCmd, for: characteristic, type: .withoutResponse) peripheralDevice?.writeValue(nextCmd, for: characteristic, type: .withoutResponse)
} }
// 根据命令类型处理设备响应 // 根据命令类型处理设备响应
switch cmd { switch cmd {
@ -953,103 +982,98 @@ private var cmdReplyType: UInt8 = 0
"command": "versionInfo", "command": "versionInfo",
"rawData": responseData "rawData": responseData
] ]
if !responseData.isEmpty { if !responseData.isEmpty {
// 如果无法解析为字符串,以点分隔的数字表示版本
let versionNums = responseData let versionNums = responseData
.map { $0 } .map { $0 }
.filter { $0 != 0xFF } // 过滤掉无效字节 .filter { $0 != 0xFF }
.map { String($0) } .map { String($0) }
.joined(separator: ".") .joined(separator: ".")
resultMap["version"] = versionNums resultMap["version"] = versionNums
os_log("接收到目标版本号(数字格式): %@", log: logger, type: .info, versionNums) os_log("接收到目标版本号(数字格式): %@", log: logger, type: .info, versionNums)
} }
notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap) notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap)
case BleConst.CMD_GET_PRODUCT_ID: case BleConst.CMD_GET_PRODUCT_ID:
var resultMap: [String: Any] = [ var resultMap: [String: Any] = [
"success": true, "success": true,
"command": "productId", "command": "productId",
"rawData": responseData "rawData": responseData
] ]
if !responseData.isEmpty { if !responseData.isEmpty {
let productId = responseData.map { String($0 & 0xFF) }.joined(separator: ".") let productId = responseData.map { String($0 & 0xFF) }.joined(separator: ".")
resultMap["productId"] = productId resultMap["productId"] = productId
os_log("接收到产品ID: %d", log: logger, type: .info, productId) os_log("接收到产品ID: %d", log: logger, type: .info, productId)
} }
notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap) notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap)
case BleConst.CMD_GET_COLOR_ID: case BleConst.CMD_GET_COLOR_ID:
var resultMap: [String: Any] = [ var resultMap: [String: Any] = [
"success": true, "success": true,
"command": "colorInfo", "command": "colorInfo",
"rawData": responseData "rawData": responseData
] ]
if !responseData.isEmpty { if !responseData.isEmpty {
let colorId = Int(responseData[0]) let colorId = Int(responseData[0])
resultMap["colorId"] = colorId resultMap["colorId"] = colorId
os_log("接收到耳机颜色ID: %d", log: logger, type: .info, colorId) os_log("接收到耳机颜色ID: %d", log: logger, type: .info, colorId)
} }
notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap) notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap)
case BleConst.CMD_GET_BATTERY_INFO: case BleConst.CMD_GET_BATTERY_INFO:
var resultMap: [String: Any] = [ var resultMap: [String: Any] = [
"success": true, "success": true,
"command": "batteryInfo", "command": "batteryInfo",
"rawData": responseData "rawData": responseData
] ]
if responseData.count >= 3 { if responseData.count >= 3 {
// 处理电池信息 - 左耳、右耳、充电仓
let leftEarBattery = Int(responseData[0] & 0x7F) let leftEarBattery = Int(responseData[0] & 0x7F)
let leftEarCharging = (responseData[0] & 0x80) != 0 let leftEarCharging = (responseData[0] & 0x80) != 0
let rightEarBattery = Int(responseData[1] & 0x7F) let rightEarBattery = Int(responseData[1] & 0x7F)
let rightEarCharging = (responseData[1] & 0x80) != 0 let rightEarCharging = (responseData[1] & 0x80) != 0
let caseBattery = Int(responseData[2] & 0x7F) let caseBattery = Int(responseData[2] & 0x7F)
let caseCharging = (responseData[2] & 0x80) != 0 let caseCharging = (responseData[2] & 0x80) != 0
// 添加到结果Map
resultMap["leftEarBattery"] = leftEarBattery resultMap["leftEarBattery"] = leftEarBattery
resultMap["leftEarCharging"] = leftEarCharging resultMap["leftEarCharging"] = leftEarCharging
resultMap["rightEarBattery"] = rightEarBattery resultMap["rightEarBattery"] = rightEarBattery
resultMap["rightEarCharging"] = rightEarCharging resultMap["rightEarCharging"] = rightEarCharging
resultMap["caseBattery"] = caseBattery resultMap["caseBattery"] = caseBattery
resultMap["caseCharging"] = caseCharging resultMap["caseCharging"] = caseCharging
resultMap["batteryLevel"] = leftEarBattery // 整体电量用左耳表示 resultMap["batteryLevel"] = leftEarBattery
os_log("接收到电量信息: 左耳=%d%% (%@), 右耳=%d%% (%@), 充电仓=%d%% (%@)", os_log("接收到电量信息: 左耳=%d%% (%@), 右耳=%d%% (%@), 充电仓=%d%% (%@)",
log: logger, type: .info, log: logger, type: .info,
leftEarBattery, leftEarCharging ? "充电中" : "未充电", leftEarBattery, leftEarCharging ? "充电中" : "未充电",
rightEarBattery, rightEarCharging ? "充电中" : "未充电", rightEarBattery, rightEarCharging ? "充电中" : "未充电",
caseBattery, caseCharging ? "充电中" : "未充电") caseBattery, caseCharging ? "充电中" : "未充电")
} else if !responseData.isEmpty { } else if !responseData.isEmpty {
// 兼容单字节电量
let batteryLevel = Int(responseData[0]) let batteryLevel = Int(responseData[0])
resultMap["batteryLevel"] = batteryLevel resultMap["batteryLevel"] = batteryLevel
os_log("接收到电量信息(简化): %d%%", log: logger, type: .info, batteryLevel) os_log("接收到电量信息(简化): %d%%", log: logger, type: .info, batteryLevel)
} }
notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap) notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap)
case BleConst.CMD_CONTROL_CODEC: case BleConst.CMD_CONTROL_CODEC:
var resultMap: [String: Any] = [ var resultMap: [String: Any] = [
"success": true, "success": true,
"command": Int(cmd), "command": Int(cmd),
"rawData": responseData "rawData": responseData
] ]
if responseData.count >= 2 { if !responseData.isEmpty && responseData.count >= 2 {
let codecStatus = Int(responseData[0]) let codecStatus = Int(responseData[0])
let channelMode = Int(responseData[1]) let channelMode = Int(responseData[1])
// 解码状态描述
let statusDesc: String let statusDesc: String
switch codecStatus { switch codecStatus {
case Int(BleConst.CODEC_CONTROL_CLOSE): case Int(BleConst.CODEC_CONTROL_CLOSE):
@ -1065,8 +1089,7 @@ private var cmdReplyType: UInt8 = 0
default: default:
statusDesc = "未知状态(\(codecStatus))" statusDesc = "未知状态(\(codecStatus))"
} }
// 声道模式描述
let channelDesc: String let channelDesc: String
switch channelMode { switch channelMode {
case Int(BleConst.AUDIO_CHANNEL_LEFT): case Int(BleConst.AUDIO_CHANNEL_LEFT):
@ -1078,19 +1101,29 @@ private var cmdReplyType: UInt8 = 0
default: default:
channelDesc = "未知声道(\(channelMode))" channelDesc = "未知声道(\(channelMode))"
} }
resultMap["codecStatus"] = codecStatus resultMap["codecStatus"] = codecStatus
resultMap["channelMode"] = channelMode resultMap["channelMode"] = channelMode
resultMap["statusDesc"] = statusDesc resultMap["statusDesc"] = statusDesc
resultMap["channelDesc"] = channelDesc resultMap["channelDesc"] = channelDesc
os_log("编解码控制响应: %@, %@", log: logger, type: .info, statusDesc, channelDesc) os_log("编解码控制响应: %@, %@", log: logger, type: .info, statusDesc, channelDesc)
} else if !responseData.isEmpty && responseData.count == 1 {
// 与 Android 保持一致:单字节且为 0 判定为错误
let codecStatus = Int(responseData[0])
if codecStatus == 0x00 {
os_log("收到设备响应: 失败, codecStatus: %d", log: logger, type: .debug, codecStatus)
resultMap = [
"success": true, // 与 Android 对齐(Dart 层按 rawData 判断)
"command": "Error",
"rawData": responseData
]
}
} }
notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap) notifyDeviceInfoReceived(infoType: Int(cmd), infoData: resultMap)
default: default:
// 对于未知命令,返回原始数据
let resultMap: [String: Any] = [ let resultMap: [String: Any] = [
"success": true, "success": true,
"command": Int(cmd), "command": Int(cmd),

Loading…
Cancel
Save