Android BLE write Характеристика блокируется наCharacteristicWrite / onCharacteristicChange - PullRequest
0 голосов
/ 11 октября 2019

У меня есть ветка сообщений для отправки буфера сообщений. Каждое сообщение ставится в очередь для отправки после успешного выполнения onCharacteristicWrite до того, как характеристика записывает следующее сообщение. Characeristic также установлен на WRITE_TYPE_NO_RESPONSE, поэтому очередь сообщений буфера довольно быстрая (приблизительно 0-7 мс) между характерными вызовами записи.

Основная проблема: характеристика "заклинившего"

По большей части это прекрасно работает. Кажется, что проблема возникает, когда есть большое количество сообщений (возможно, происходит с меньшим количеством сообщений, но более заметно при отправке большого количества сообщений). Происходит вызов writeCharacteristic, и, похоже, характеристика блокируется, поскольку onCharacteristicChanged больше не считывает новые данные и не получает onCharacteristicWrite.

Другие вещиЯ заметил:

  1. Добавление задержки в 5-10 мс после каждого characteristicWrite, кажется, помогает, но я не понимаю, зачем нужен объект Bluetooth GATTзадержка, когда onCharacteristicWrite возвращается успешно.

  2. Иногда я получаю обратный вызов в onConnectionStateChange со статусом 8, устройство вне диапазона. Хотя это не всегда происходит.

  3. Иногда characteristicWrite возвращает false;однако он также может возвращать значение true перед переходом в состояние «характеристики заклинивания», описанное выше

Сообщение Код потока:

    private boolean stopMessageThread = false;
    private boolean characteristicWriteSuccessful = true;
    private ArrayList<byte[]> messageQueue = new ArrayList<byte[]>();
    private Thread messageThread =  new Thread( new Runnable() {
        private long lastTime = 0;
        private int count = 0;
        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted() && !stopMessageThread) {
                if(messageQueue.size() != 0 && characteristicWriteSuccessful) {

                    Log.i(TAG, ""+(System.currentTimeMillis()-lastTime));
                    Log.i(TAG, "Queue count: "+messageQueue.size());

                    characteristicWriteSuccessful = false;
                    byte[] message = messageQueue.remove(0);
                    customCharacteristic.setValue(message);
                    boolean status = bluetoothGatt.writeCharacteristic(customCharacteristic);

                    Log.i(TAG, "write characteristic status "+status);

                    lastTime = System.currentTimeMillis();
                    //sleep(10); // this kinda helps but can still throw the error
                }
            }
        }
    });

1 Ответ

1 голос
/ 12 октября 2019

Помимо занятого ожидания, которое может заблокировать весь процессор и быстро разрядить батарею, я не вижу никакой синхронизации. Существуют общие структуры данных (вероятно, stopMessageThread, characteristicWriteSuccessful и messageQueue) и несколько потоков, обращающихся к ним. Без синхронизации произойдут условия гонки, и застревание может быть проявлением этого.

Поэтому я предлагаю перейти к более простому дизайну, в частности, без потока для отправки сообщений:

private ArrayList<byte[]> messageQueue = new ArrayList<byte[]>();
private boolean isSending = false;

void sendMessage(<byte[]> message) {
    synchronized (this) {
        if (isSending) {
            messageQueue.add(message);
            return;
        }
        isSending = true;
    }
    bluetoothGatt.writeCharacteristic(customCharacteristic);
}

public void onCharacteristicWrite (BluetoothGatt gatt, 
                BluetoothGattCharacteristic characteristic, 
                int status) {
    byte[] message;
    synchronized (this) {
        if (messageQueue.size() == 0) {
            isSending = false;
            return;
        }
        message = messageQueue.remove(0);
    }
    bluetoothGatt.writeCharacteristic(customCharacteristic); 
}

В этом решении предполагается, что writeCharacteristic не блокируется и работает быстро. Это безопасное предположение, так как метод асинхронный по своей конструкции: у него есть обратный вызов, который будет вызван после завершения операции.

Таким образом, обратный вызов onCharacteristicWrite используется для отправки следующего сообщения в буфере. Следовательно, необходимость в потоке исчезает - и, следовательно, исчезает и связанная с этим сложность.

По-прежнему задействовано несколько потоков, поскольку обратный вызов вызывается из фонового потока. Поэтому доступ к общим данным синхронизируется.

...