You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CBPeripheral WriteValue无断点时不调用代理方法的问题求助

问题分析与解决方案

你遇到的是典型的蓝牙异步写入的速率控制问题——调试时断点给了外设足够的时间处理每个固件块,但正常运行时你可能在连续快速调用makeFWBLOCK,而CBPeripheral.writeValue(_:for:type:)是异步操作,外设还没处理完上一个包就收到了下一个,导致丢包或处理失败。

核心问题拆解

蓝牙BLE的withResponse写入需要外设返回确认包后,才算完成一次写入。你的代码目前没有等待这个确认,而是连续触发写入,外设无法跟上这个速率,自然会失败;而断点相当于强制暂停了发送节奏,给了外设足够的处理时间,所以调试时能成功。

具体修复方案

1. 引入写入状态控制与回调驱动的发送逻辑

你需要实现回调触发下一次写入的机制,确保只有当上一个固件块写入成功并收到外设确认后,再发送下一个块。

首先,在你的类中添加几个状态变量:

// 标记当前是否正在进行蓝牙写入
private var isWritingFirmware = false
// 当前要发送的固件位置
private var currentFWPos = 0

2. 修改makeFWBLOCK为可触发单次写入的方法

调整方法,去掉自动累加位置的逻辑,改为依赖回调更新位置:

func sendFWBlock(at position: Int) {
    guard !isWritingFirmware else {
        // 如果正在写入,直接返回避免并发
        return
    }
    isWritingFirmware = true
    
    let totalCallCount = (position / 128) + 1
    print("total Call Count ----- ", totalCallCount)
    
    var txlen = 128
    if (byteArray.count - position) < 128 {
        txlen = byteArray.count - position
    }
    
    // 以下是你原有的数据包构建逻辑,保留不变
    let dataForPayloadSize = NSData(bytes: [6 + txlen], length: 2)
    var resultPayloadSize = [UInt8](repeating: 0, count: 2)
    dataForPayloadSize.getBytes(&resultPayloadSize, length: 2)
    
    let dataForMajor = NSData(bytes: [4], length: 1)
    var resultMajor = [UInt8](repeating: 0, count: 1)
    dataForMajor.getBytes(&resultMajor, length: 1)
    
    let dataForMinor = NSData(bytes: [5], length: 1)
    var resultMinor = [UInt8](repeating: 0, count: 1)
    dataForMinor.getBytes(&resultMinor, length: 1)
    
    let dataForSuffix = NSData(bytes: [65], length: 1)
    var resultSuffix = [UInt8](repeating: 0, count: 1)
    dataForSuffix.getBytes(&resultSuffix, length: 1)
    
    let numberOfChunks = (txlen / 64) + (((txlen % 64) > 0) ? 1 : 0)
    let dataForNumberOfChunks = NSData(bytes: [numberOfChunks], length: 1)
    var resultNumberOfChunks = [UInt8](repeating: 0, count: 1)
    dataForNumberOfChunks.getBytes(&resultNumberOfChunks, length: 1)
    
    let offset = position / 64
    let dataForOffset = NSData(bytes: [offset], length: 2)
    var resultOffset = [UInt8](repeating: 0, count: 2)
    dataForOffset.getBytes(&resultOffset, length: 2)
    
    var value: [UInt8] = [0x02]
    value.append(resultPayloadSize[0])
    value.append(resultPayloadSize[1])
    value.append(resultMajor[0])
    value.append(resultMinor[0])
    value.append(resultSuffix[0])
    value.append(resultNumberOfChunks[0])
    value.append(resultOffset[0])
    value.append(resultOffset[1])
    
    let start = offset * 64
    let end = start + txlen - 1
    value.append(contentsOf: byteArray[start...end])
    
    let remaining = (byteArray.count - 1) - end
    print("remaining:", remaining)
    
    let data = Data(bytes: value)
    self.pheripharal_To_Connect?.writeValue(data, for: BluetoothManager.SharedInstance.characteristic!, type: .withResponse)
}

3. 实现CBPeripheralDelegate的写入回调

在你的蓝牙代理类中,实现didWriteValueFor方法,处理写入结果并触发下一次写入:

func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
    guard characteristic == BluetoothManager.SharedInstance.characteristic else {
        return
    }
    
    isWritingFirmware = false
    
    if let error = error {
        // 写入失败,这里可以添加重试逻辑
        print("Firmware block write failed: \(error.localizedDescription)")
        // 可选:重试当前块
        sendFWBlock(at: currentFWPos)
        return
    }
    
    // 写入成功,更新位置并发送下一个块
    currentFWPos += 128
    if currentFWPos < byteArray.count {
        sendFWBlock(at: currentFWPos)
    } else {
        // 所有块发送完成,固件更新结束
        print("Firmware update completed successfully!")
    }
}

4. 启动固件更新的入口方法

添加一个启动方法,初始化状态并发送第一个块:

func startFirmwareUpdate() {
    currentFWPos = 0
    isWritingFirmware = false
    sendFWBlock(at: currentFWPos)
}

额外注意事项

  • 确保你的类已经设置为CBPeripheral的代理(peripheral.delegate = self),否则无法收到写入回调。
  • 可以添加超时机制:如果一段时间内没收到写入回调,主动重试当前块。
  • 外设端也要确保能正确处理每个块并返回确认,如果你能修改外设固件,也要检查其接收速率和响应逻辑。

内容的提问来源于stack exchange,提问作者Nikh1414

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:18:48