Android 正在调用onCharacteristicWrite(),但它没有';我不总是写信

Android 正在调用onCharacteristicWrite(),但它没有';我不总是写信,android,bluetooth,bluetooth-lowenergy,android-bluetooth,android-ble,Android,Bluetooth,Bluetooth Lowenergy,Android Bluetooth,Android Ble,我有一个定制的带有蓝牙低能量芯片的硬件。我用一个500个U32的数组来设置它,这样数组[n]==n。我正在开发一个android应用程序,它可以连接到设备,请求阵列的长度,然后一次一个请求阵列中的数据点 android应用程序似乎基本上运行良好。它连接到设备,请求长度,并在收到前一段数据后继续请求下一段数据。但是,在数组的中途(在-中的2到450个元素之间似乎不一致),它将编写另一个命令,并一直执行到onCharacteristicWrite(),但它从未收到响应。我将我的BLE外设连接到Coo

我有一个定制的带有蓝牙低能量芯片的硬件。我用一个500个U32的数组来设置它,这样数组[n]==n。我正在开发一个android应用程序,它可以连接到设备,请求阵列的长度,然后一次一个请求阵列中的数据点

android应用程序似乎基本上运行良好。它连接到设备,请求长度,并在收到前一段数据后继续请求下一段数据。但是,在数组的中途(在-中的2到450个元素之间似乎不一致),它将编写另一个命令,并一直执行到onCharacteristicWrite(),但它从未收到响应。我将我的BLE外设连接到CoolTerm,它甚至从未收到命令。以下是我的代码和日志中的片段:

服务:

 private final BluetoothGattCallback bleGattCallback = new BluetoothGattCallback() {

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicRead(gatt, characteristic, status);
        Log.d("onCharacteristicRead", byteArrToHex(characteristic.getValue()));
    }

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        if(status != BluetoothGatt.GATT_SUCCESS){
            Log.d("onCharacteristicWrite", "Failed write, retrying");
            gatt.writeCharacteristic(characteristic);
        }
        Log.d("onCharacteristicWrite", byteArrToHex(characteristic.getValue()));
        super.onCharacteristicWrite(gatt, characteristic, status);
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);
        Log.d("onCharacteristicChanged", byteArrToHex(characteristic.getValue()));
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
    }

};
我省略了回调中与描述符写入、连接状态更改等相关的不必要部分。当广播数据时,将在MainActivity的这一部分接收数据:

private BroadcastReceiver messageReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String receivedUUID = intent.getStringExtra("uuid");
        byte[] data = intent.getByteArrayExtra("data");
        Log.d("messageReceiver", "received intent in mainActivity with uuid " + receivedUUID.toString());
        if(receivedUUID.equals(READ_LEN_UUID.toString()) && currentlyReading) {
            datapoints = new ArrayList<Long>();
            numberOfDatapoints = 0;
            numberOfDatapoints |= (data[0] & 0xff);
            numberOfDatapoints |= (data[1] & 0xff) << 8;
            numberOfDatapoints |= (data[2] & 0xff) << 16;
            numberOfDatapoints |= (data[3] & 0xff) << 24;
            Log.d("RECEIVER TEST:", "number of datapoints = " + numberOfDatapoints);

            if(numberOfDatapoints > 0) {
                bleService.requestDatapoint(0);
            }
        } else if (receivedUUID.equals(READ_DATAPOINT_UUID.toString()) && currentlyReading){
            long message = 0;
            message |= (data[0] & 0xff);
            message |= (data[1] & 0xff) << 8;
            message |= (data[2] & 0xff) << 16;
            message |= (data[3] & 0xff) << 24;

            Log.d("Datapoint Recieved", "Index " + datapoints.size() + " = " + message);
            datapoints.add(message);

            if(datapoints.size() < numberOfDatapoints){
                bleService.requestDatapoint(datapoints.size());
            }
        }
    }
};
我相当肯定发送命令太快没有问题。它实际上非常慢,这是我故意做的,这样我可以在进入下一个项目之前更容易地测试东西

我的一个调试日志中的代码段:

08-23 12:08:18.470 16753-16753/sethp.datalogcollector D/requestDatapoint: Requested datapoint at 49
08-23 12:08:18.570 16753-16765/sethp.datalogcollector D/onCharacteristicWrite: 02 31 00 
08-23 12:08:18.570 16753-16765/sethp.datalogcollector D/onCharacteristicChanged: 31 00 00 00 
08-23 12:08:18.570 16753-16765/sethp.datalogcollector D/BLEService: Characteristic found. UUID: 00020000-5f5f-4a49-4847-464544434241
08-23 12:08:18.575 16753-16753/sethp.datalogcollector D/messageReceiver: received intent in mainActivity with uuid 00020000-5f5f-4a49-4847-464544434241
08-23 12:08:18.575 16753-16753/sethp.datalogcollector D/Datapoint Recieved: Index 49 = 49
08-23 12:08:18.575 16753-16753/sethp.datalogcollector D/requestDatapoint: Requested datapoint at 50
08-23 12:05:55.585 16753-16765/sethp.datalogcollector D/onCharacteristicWrite: 02 32 00 
08-23 12:05:55.585 16753-16765/sethp.datalogcollector D/onCharacteristicChanged: 32 00 00 00 
08-23 12:05:55.585 16753-16765/sethp.datalogcollector D/BLEService: Characteristic found. UUID: 00020000-5f5f-4a49-4847-464544434241
08-23 12:05:55.585 16753-16753/sethp.datalogcollector D/messageReceiver: received intent in mainActivity with uuid 00020000-5f5f-4a49-4847-464544434241
08-23 12:05:55.590 16753-16753/sethp.datalogcollector D/Datapoint Recieved: Index 50 = 50
08-23 12:05:55.590 16753-16753/sethp.datalogcollector D/requestDatapoint: Requested datapoint at 51
08-23 12:05:55.680 16753-16845/sethp.datalogcollector D/onCharacteristicWrite: 02 33 00 
08-23 12:05:55.685 16753-16764/sethp.datalogcollector D/onCharacteristicChanged: 33 00 00 00 
08-23 12:05:55.685 16753-16764/sethp.datalogcollector D/BLEService: Characteristic found. UUID: 00020000-5f5f-4a49-4847-464544434241
08-23 12:05:55.685 16753-16753/sethp.datalogcollector D/messageReceiver: received intent in mainActivity with uuid 00020000-5f5f-4a49-4847-464544434241
08-23 12:05:55.685 16753-16753/sethp.datalogcollector D/Datapoint Recieved: Index 51 = 51
08-23 12:05:55.685 16753-16753/sethp.datalogcollector D/requestDatapoint: Requested datapoint at 52
08-23 12:05:55.785 16753-16765/sethp.datalogcollector D/onCharacteristicChanged: 34 00 00 00 
08-23 12:05:55.785 16753-16765/sethp.datalogcollector D/BLEService: Characteristic found. UUID: 00020000-5f5f-4a49-4847-464544434241
08-23 12:05:55.785 16753-16753/sethp.datalogcollector D/messageReceiver: received intent in mainActivity with uuid 00020000-5f5f-4a49-4847-464544434241
08-23 12:05:55.785 16753-16753/sethp.datalogcollector D/Datapoint Recieved: Index 52 = 52
08-23 12:05:55.785 16753-16753/sethp.datalogcollector D/requestDatapoint: Requested datapoint at 53
08-23 12:05:55.790 16753-16765/sethp.datalogcollector D/onCharacteristicWrite: 02 35 00 
以及我相应的CoolTerm日志片段:

command: 02
index: 0031
command = 2
datapoint at 49 = 49
attempting to send 49

command: 02
index: 0032
command = 2
datapoint at 50 = 50
attempting to send 50

command: 02
index: 0033
command = 2
datapoint at 51 = 51
attempting to send 51

command: 02
index: 0034
command = 2
datapoint at 52 = 52
attempting to send 52
注意,在我的外设日志中,它似乎没有收到对数据点53的请求。 作为参考,onCharacteristicWrite调试中的第一个十六进制字节是命令。命令02仅仅意味着我正在请求一个数据点,该数据点位于下2个字节包含的任何内容的索引处

我注意到在Android日志中,没有用于请求datapoint 51的onCharacteristicWrite日志。这种情况似乎每次都发生在它停止获取数据之前,但我不确定这是否重要,或者这只是日志缓冲区的问题

我已经运行了很多测试,试图发现任何模式,并且我已经注意到,当设备未连接到调试电缆时,它似乎会获得更多的数据点。此时我唯一的想法是,可能我遇到了异步中断回调的问题,但我不知道该怎么做。有没有人想过为什么调用onCharacteristicWrite后它似乎并没有实际写入数据

谢谢

编辑:

我按照埃米尔的建议打开了蓝牙日志。我和wireshark玩了一圈,弄清楚发生了什么事。我再次试用了我的应用程序,它一直运行到索引102,直到它停止,这时我断开了设备的连接。我翻遍了Wireshark中的数据包,发现我的设备确实收到了关于102的数据,但它没有发送103的请求。我仔细检查了我的android日志,onCharacteristicWrite内部的日志语句说它发送了命令026700,这是对103的请求。因此,似乎正在调用onCharacteristicWrite,但实际上并未写入该特性

经过更多的观察和思考,我很确定1)onCharacteristicWrite被不正确地调用,因为数据从未被写入,或者2)不知何故,某个异步的东西正在中断它并阻止它传输。我不知道该怎么做

最终编辑:

尽管,据我从规范中了解,onCharacteristicWrite只应在可靠、成功的写入过程中调用,但我决定检查writeCharacteristic的返回值。我应该在几个小时前检查一下。你知道吗,上次的请求返回了false


我认为调用onCharacteristicWrite(即使返回值为false)是一个错误。我已经读到,使用onCharacteristicWrite调用写入下一个数据块是安全的。要么是他们错了,要么是这里出了什么事。不管怎样,我想检查那些函数调用返回值都是一个不错的主意。

现在我想我看到了。有时,通知在onWriteCharacteristic回调之前到达。由于在通知回调中发出下一次写入,因此上一次写入仍处于挂起状态。在进行下一次写入之前,您必须确保已调用onWriteCharacteristic。

能否显示实际调用writeCharacteristic的代码?当然,现在添加它看起来很奇怪。你用还是不用?此外,您可以尝试启用bluetooth hci snoop日志,然后在Wireshark中检查它,以查看通过空中传送的内容。我在Android中没有对此进行修改,但在固件级别上,我的特征定义为CHAR_PROP_WRITE=0x08,这与属性_WRITE的值相同。我还没有尝试过,我将在谷歌上搜索如何做到这一点并尝试一下。writeCharacteristic返回false的最常见原因是因为已经有另一个GATT操作正在进行(读/写特征/描述符)。您是否有其他代码执行其他GATT操作?您可以看到,如果writeCharacteristic方法返回false,它将永远不会启动写入操作。您确定吗?例如,如果我想要数据点7,我将编写该请求,然后在成功写入时调用onCharacteristicWrite,然后在收到响应时调用OnCharacteristicChanged,此时我将请求数据点8。是否有可能在收到响应之前不调用onCharacteristicWrite?是的,当您的外围设备发回GATT写入响应时,将调用onCharacteristicWrite。由于它在同一时间发回通知,我猜它是未定义的,首先传递给应用程序的是哪个。在logcat日志中,与先前的数据包相比,在通知之后检索最后一次写入响应。因为characteristic.getValue()包含最后一个值
command: 02
index: 0031
command = 2
datapoint at 49 = 49
attempting to send 49

command: 02
index: 0032
command = 2
datapoint at 50 = 50
attempting to send 50

command: 02
index: 0033
command = 2
datapoint at 51 = 51
attempting to send 51

command: 02
index: 0034
command = 2
datapoint at 52 = 52
attempting to send 52