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

问题描述:

我试图使用Android SPP蓝牙套接字接口实时控制/操作来自Android手机的电机。电机应该以所谓的“死人”运行模式运行。所以只有当android APP上的按钮被触摸时,电机才会转动,如果触摸被释放,应该立即停止。Android蓝牙SPP - 如何停止传输内部发送缓冲区?

我通过每20ms不断发送20个字节的“保持转动”报文来实现此目的,以保持电机转动,并且一旦没有收到更多报文或收到停止报文,马达立即停止。

这似乎在某些电话上可以正常工作,但其他人在处理完MotionEvent.ACTION_UP事件并且没有更多数据正在发送之后仍继续发送'继续转动'报文。

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

简单的问题:

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

在网络搜索中,我找不到任何关于缓冲区管理的BT流缓冲区大小的内容。

是的,我已经将读写功能实现为线程,并且在读取所有电报时没有任何问题,并且我不需要实时发送电报,但是我应该能够停止发送“继续转动'在大约50到100毫秒内发送电报。

任何提示都非常受欢迎。

+0

这是一个非常不可能的问题没有真正看到你的代码来回答的线索。我们不知道你实际在做什么(而不是你想做什么),所以我们不能告诉你,如果你做错了什么。 – 2015-01-09 18:48:00

我很抱歉,我没有添加代码,我认为它是直线前进,因为它可能没有必要:

@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直到按钮被释放。 此方法工作得很好,因为发送缓冲区一次不会保存多个报文。

提到的问题虽然解决了,但我仍然没有它是否有可能清除发送缓冲器