Смущает BluetoothGattServerCallback # onCharacteristicWriteRequest

Замутил метод Android BluetoothGattServerCallback # onCharacteristicWriteRequest.

  1. Что касается параметра preparedWrite, я думал, что это моя обязанность реализовать операцию записи, как обратный вызов узнает, когда я должен поставить сообщение в очередь?

  2. В документации написано An application must call BluetoothGattServer.sendResponse(BluetoothDevice, int, int, int, byte[]) to complete the request., что, если responseNeeded ложный?

  3. Вызов BluetoothGattServer#sendResponse(BluetoothDevice, int, int, int, byte[]), кажется, всегда возвращает значение в запросе, независимо от того, что я установил для value. Ожидается?

1
0
398
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

preparedWrite используется для поддержки длинных записей (больше MTU).

BluetoothGattServerCallback#onCharacteristicWriteRequest работает вместе с BluetoothGattServerCallback#onExecuteWrite для повторной сборки фрагментированных данных, отправленных одноранговым устройством. Чтобы ответить на ваши вопросы:

  1. Параметр preparedWrite истинен, когда получен фрагмент входящих данных, т.е. данные должны быть поставлены в очередь до тех пор, пока не прибудут другие. BluetoothGattServerCallback#onExecuteWrite будет вызываться после того, как будет получен последний фрагмент, и отправленное значение характеристики может быть полностью собрано.

  2. Если responseNeeded ложный, не звоните в BluetoothGattServer.sendResponse(BluetoothDevice, int, int, int, byte[]).

  3. Просто отправьте пустой value.

    Вот пример onCharacteristicWriteRequest:

                @Override
                public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
                    super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
                    Log.d("SVC", "BluetoothGattServerCallback.onCharacteristicWriteRequest with " + value.length + " bytes");
                    if (preparedWrite) {
                        handleInputFragment(device, characteristic.getUuid(), value);
                    } else {
                        handleInputMessage(device, characteristic.getUuid(), value);
                    }
                    if (responseNeeded) {
                        Log.d("SVC", "sending response to write request for characteristic: " + characteristic.getUuid());
                        if (!gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, new byte[0])) {
                            Log.e("SVC", "response to characteristic write request failed");
                        }
                    }
                }

и onExecuteWrite

                @Override
                public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
                    Log.d("SVC", "BluetoothGattServerCallback.onExecuteWrite " + (execute ? "execute" : "cancelled"));
                    super.onExecuteWrite(device, requestId, execute);
                    Iterator<InputBuffer> itr = inputBuffers.iterator();
                    while(itr.hasNext()) {
                        InputBuffer buf = itr.next();
                        if (buf.device.equals(device)) {
                            itr.remove();
                            if (execute) {
                                ByteArrayOutputStream os = new ByteArrayOutputStream();
                                for (byte[] b : buf.bytes) {
                                    os.write(b, 0, b.length);
                                }
                                handleInputMessage(device, buf.characteristicUuid, os.toByteArray());
                            }
                        }
                    }
               }

Реализация механизма InputBuffer выглядит примерно так:

    private class InputBuffer {
        final BluetoothDevice device;
        final UUID characteristicUuid;
        final List<byte[]> bytes;

        InputBuffer(BluetoothDevice device, UUID characteristicUuid, byte[] value) {
            this.device = device;
            this.characteristicUuid = characteristicUuid;
            this.bytes = new ArrayList<>();
            this.bytes.add(value);
        }
    }

    private List<InputBuffer> inputBuffers = new LinkedList<>();

    private void handleInputFragment(BluetoothDevice device, UUID characteristicUuid, byte[] value) {
        Log.d("SVC", "handling input Fragment");
        for(InputBuffer buf : inputBuffers) {
            if (buf.device.equals(device)) {
                buf.bytes.add(value);
                return;
            }
        }
        inputBuffers.add(new InputBuffer(device, characteristicUuid, value));
    }

Реализация handleInputMessage зависит от приложения.

Спасибо, что нашли время и усилия, чтобы объяснить детали, я потрачу время, чтобы попробовать это сам.

Dino Tw 16.09.2019 22:15

Другие вопросы по теме