Android蓝牙SPP - 如何停止传输内部发送缓冲区?

时间:2015-01-09 18:43:38

标签: android bluetooth spp

我正试图在尽可能接近的情况下从Android手机控制/操作电机"实时使用Android SPP蓝牙套接字接口。电机应该运行在一个所谓的“死人”中。操作模式。因此,只有触摸Android APP上的按钮才会转动电机,如果触摸被释放则应立即停止。

我通过不断发送'继续转向'来实现这一点。大约每20毫秒20字节的电报,以便在没有收到电报或收到停止电报时立即停止电机转动并立即停止电机。

这似乎在某些手机上可以接受,但其他人继续发送'继续转动'即使在处理了MotionEvent.ACTION_UP事件并且不再发送数据之后,也会发送电报。

我认为这是由一些内部缓冲区引起的,这些缓冲区缓存传输数据并继续发送,直到缓冲区为空。

简单问题:

  • 有没有办法清除BT流发送缓冲区以立即停止所有数据传输?
  • 或者我可以获得发送缓冲区的填充级别,在这种情况下,我不会将大约2个电报放入其中吗?
  • 或者有没有办法在打开流时指定缓冲区大小?

在网上搜索时,我无法找到任何有关缓冲区管理的BT流缓冲区大小的内容。

是的,我已经实现了读取和写入功能作为线程,我在阅读所有电报时没有任何问题,我不需要实时发送电报,但我应该能够停止发送'继续转向'电报在50到100毫秒之内。

非常欢迎任何提示。

1 个答案:

答案 0 :(得分:0)

对不起,我没有添加代码,我认为可能没有必要,因为它是直截了当的:

    @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;
    }

下面的剪辑是管理蓝牙串行通信的通信类的一部分。

 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();
             }
         }
     }
 }

代码剪断分配并打开蓝牙连接

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));

我从未发现通过此代码发送和接收数据有任何问题。正确发送和接收所有记录。唯一的问题是,在释放操作按钮时我无法清除发送缓冲区。

为了克服这个问题,我已经改变了协议,只有一个人继续转向'电报一次发送,下一个电报将在另一端发出响应后发送(有点握手),然后程序继续运行此ping / pong,直到按钮被释放。 这种方法非常有效,因为传输缓冲区一次不会持有多个电报。

虽然解决了上述问题,但我仍然不知道是否可以清除发送缓冲区