Android Bluetooth SPP - Как остановить передачу внутреннего буфера отправки?

Я пытаюсь управлять/управлять двигателем с телефона Android в «максимально близком» режиме реального времени, используя интерфейс Bluetooth-сокета Android SPP. Двигатель должен работать в так называемом режиме «мертвого человека». Таким образом, двигатель будет вращаться только при нажатии кнопки в приложении для Android и должен немедленно остановиться, если отпустить касание.

Я реализовал это, непрерывно отправляя 20-байтовые телеграммы «продолжать вращение» примерно каждые 20 мс, чтобы двигатель продолжал вращаться и немедленно останавливался, как только больше не поступают телеграммы или если получена телеграмма STOP.

Кажется, что это работает приемлемо хорошо на некоторых телефонах, но другие продолжают отправлять телеграммы «продолжать переворачивать» даже после обработки события MotionEvent.ACTION_UP и отправки данных.

Я предполагаю, что это вызвано некоторыми внутренними буферами, которые кэшируют передаваемые данные и продолжают отправлять до тех пор, пока буфер не станет пустым.

Простые вопросы:

  • Есть ли способ очистить буфер передачи потока BT, чтобы немедленно остановить передачу всех данных?
  • Или можно получить уровень заполнения передающего буфера, в таком случае я бы не клал в него ничего больше, чем около 2-х телеграмм?
  • Или есть способ указать размер буфера при открытии потока?

Поискав в сети, я не смог найти ничего, что говорило бы о размере буфера потока BT для управления буфером.

И да, я реализовал функции чтения и записи в виде потоков, и у меня нет проблем с чтением всех телеграмм, и мне не нужно доставлять телеграммы в режиме реального времени, но я должен иметь возможность прекратить отправку телеграмм «продолжать переворачивать» в течение примерно от 50 до 100 мс.

Любые подсказки очень приветствуются.


person Peter    schedule 09.01.2015    source источник
comment
На этот вопрос невозможно ответить, не видя вашего кода. Мы понятия не имеем, что вы на самом деле делаете (в отличие от того, что вы пытаетесь сделать), поэтому мы не можем сказать вам, делаете ли вы что-то не так.   -  person Gabe Sechan    schedule 09.01.2015


Ответы (1)


Мне жаль, что я не добавил код, я подумал, что это может быть не нужно, так как это прямолинейно, как:

    @Override
    public boolean onTouch(final View v,MotionEvent event) {
        int eventAction = event.getAction();

        switch (eventAction) {
            case MotionEvent.ACTION_DOWN:
                if (v == btnUp || v == btnDown) {

                    // Start a thread that sends the goUP or DOWN command every 10 ms until
                    // btnUp released

                    tvCounter.setText("----");
                    action_touched = true;

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            int counter = 1;

                            // Disable heart beat
                            ServiceRequest.send(EnRequest.REQ_SET_HEARTBEAT,0);

                            // Send GoUp command plus a wrapping counter byte every nn ms
                            // until the button is released

                            while (action_touched) {
                                try {
                                    setDeadmanMove(v==btnUp,counter);
                                    Thread.sleep(20);
                                    ++counter;
                                }
                                catch (InterruptedException ex) {
                                    action_touched = false;
                                }
                                catch (Exception ex) {
                                    action_touched = false;
                                }
                            }

                            // Send a STOP command
                            setDeadmanStop();

                            // Enable heart beat again
                            ServiceRequest.send(EnRequest.REQ_SET_HEARTBEAT,1);

                            // We are done
                        }
                    }).start();
                }
                break;

            case MotionEvent.ACTION_UP:
                // Stop Thread
                action_touched = false;
                break;
        }
        return true;
    }

Вырезанное ниже является частью класса связи, который управляет последовательной связью Bluetooth.

 public void btWrite(DeviceRecord message) {
     if (runBTreceiver) {

         if (message.isValidRecord()) {
             try {

                 lock.lock();
                 ++lockCounter;
                 mmBufferedOut.write(message.getFullRecord());
                 mmBufferedOut.flush();
             }
             catch (IOException e) {
                 if (GlobalData.isDebugger) Log.i(TAG, "Failed sending " + message + " " + e.getMessage());
                 ServiceResponse.send(EnEvent.EVT_BT_RECEIVER_ERROR, "Error data send: " + e.getMessage());
                 resetConnection();
                 runBTreceiver=false;
             }
             finally {
                 --lockCounter;
                 lock.unlock();
             }
         }
     }
 }

Вырезан код, который выделяет и открывает соединение Bluetooth

try {
    // Set up a pointer to the remote node using it's address.
    BluetoothDevice device = myBluetoothAdapter.getRemoteDevice(myBluetoothMacId);
    if (device != null)
    {
        // Two things are needed to make a connection:
        // A MAC address, which we got above.
        // A Service ID or UUID. In this case we are using the
        // UUID for SPP.

        try {
            myBluetoothSocket = device.createRfcommSocketToServiceRecord(GlobalData.MY_UUID);
        }
        catch (IOException e) {
            sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL,
                    String.format(GlobalData.rString(R.string.srv_failcrt),BTERROR_CREATE,e.getMessage()));
        }

        // Establish the connection. This will block until it connects or
        // timeout?

        try {
            if (! myBluetoothSocket.isConnected()) {
                myBluetoothSocket.connect();
            }
        }
        catch (IOException e) {
            try {
                Log.e("","trying fallback...");

                myBluetoothSocket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);
                myBluetoothSocket.connect();
            }
            catch (IOException e2) {
                sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL,e2.getMessage());
            }
        }
    }
    else {
        sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL,
                String.format(GlobalData.rString(R.string.srv_failcrt),BTERROR_DEVICE,"getRemoteDevice failed"));
    }
}
catch (Exception e) {
    sendEventStatus(EnEvent.EVT_BTADAPTER_FAIL, e.getMessage());
    return;
}
InputStream tmpIn = null;
OutputStream tmpOut = null;

mmSocket = socket;

// Get the input and output streams, using temp objects because
// member streams are final

try {
    tmpIn = socket.getInputStream();
    tmpOut = socket.getOutputStream();
}
catch (IOException e) {
    ServiceResponse.send(EnEvent.EVT_ERROR, GlobalData.rString(R.string.srv_failcst) + e.getMessage());
    resetConnection();
    runBTreceiver=false;
}
mmInStream = tmpIn;
// mmOutStream = tmpOut;
mmBufferedOut = new BufferedOutputStream(tmpOut,80);

// Initial request
btWrite(new DeviceRecord(0, 4));

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

Чтобы преодолеть эту проблему, я изменил протокол таким образом, что за один раз отправляется только одна телеграмма «продолжать вращаться», следующая телеграмма будет отправлена ​​после ответа с другого конца (своего рода рукопожатие), Затем программа продолжает выполнять этот пинг/понг до тех пор, пока кнопка не будет отпущена. Этот метод работает очень хорошо, так как буфер передачи никогда не будет хранить более одной телеграммы за раз.

упомянутая проблема решена, но я до сих пор не знаю, можно ли очистить буфер передачи

person Peter    schedule 11.01.2015