- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个自制的蓝牙设备以 500Hz 的频率测量心电图:设备每 2 毫秒发送 9 个字节的数据(标题、心电图测量值、页脚)。所以这大概是一个9*500=4.5kbytes/s的数据流。
我有一个 C++ Windows 程序能够连接设备并检索数据流(使用 Qt/qwt 显示)。在这种情况下,我使用 Windows 控制面板绑定(bind)设备,并使用 boost serial_port 接口(interface)通过虚拟 COM 端口连接它。这非常有效,我正在实时接收我的数据流:我每 2 毫秒左右获得一个测量点。
我通过 QtCreator (Qt 5.3.2) 在 Android 上移植了整个 C++ 程序。我遇到了实时问题。前 5 秒数据流是“实时”的,然后性能会急剧下降(参见 How to do good real-time data streaming using Java Android SDK )。
因为我认为问题可能是由于 C++/Qt 引起的,我使用 Eclipse 编写了一个完全空白的纯 Java/Android 项目。它有同样的问题!!!
问题是:这段代码有问题吗?为什么我只接收前 5 秒的实时数据?在 Android 平台上密集使用 BT 5 秒后会发生什么,为什么会减慢 BT 数据接收速度?
这是我的 Java 程序:
BluetoothHelper.java(具有连接/断开/读写数据功能:
package com.example.helloworld;
import android.util.Log;
import android.content.Context;
import android.os.Bundle;
import java.util.Locale;
import java.util.concurrent.Semaphore;
import java.lang.String;
import java.lang.Thread;
import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.lang.InterruptedException;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.bluetooth.BluetoothManager;
import android.util.SparseArray;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import java.util.UUID;
import java.util.Date;
import java.util.Calendar;
import java.util.Vector;
import java.util.Set;
import java.util.Arrays;
public class BluetoothHelper
{
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothDevice mDevice;
private BluetoothSocket mSocket;
private OutputStream mOutputStream;
private InputStream mInputStream;
private BroadcastReceiver mReceiver;
private Activity myActivity;
private Vector<BluetoothDevice> mDevices;
private byte[] mHeader;
private byte[] mFrame;
public BluetoothHelper(Activity a)
{
myActivity = a;
mHeader = new byte[3];
mFrame = new byte[256];
mDevices = new Vector();
}
/* Check bluetooth is enabled, return "" if OK, else, return error string */
public String initializeBluetooth(){
String error = "";
System.out.println("Initializing bluetooth...");
mBluetoothManager = (BluetoothManager) myActivity.getSystemService(Context.BLUETOOTH_SERVICE);
if ( mBluetoothManager == null )
{
error = "Bluetooth manager is not found";
}
else
{
mBluetoothAdapter = mBluetoothManager.getAdapter();
if( mBluetoothAdapter == null )
{
error = "Bluetooth adapter is not found";
}
else if( ! mBluetoothAdapter.isEnabled() )
{
error = "Bluetooth adapter is off";
}
else
{
System.out.println("Bluetooth successfully initialized");
return "";
}
}
return error;
}
private void addDevice( final BluetoothDevice device )
{
mDevices.add(device);
}
public Vector<BluetoothDevice> getDevices() { return mDevices; }
/* Clear previously detected device list */
public boolean clearDeviceList(){
// Clear old list
mDevices.clear();
return true;
}
/* Fill local device list with paired devices */
public boolean addPairedDevices(){
//System.out.println("Entering addPairedDevices");
if( mBluetoothAdapter == null )
{
System.out.println("No bluetooth adapter");
return false;
}
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0)
{
//System.out.println("Found paired devices");
// Loop through paired devices
for (BluetoothDevice device : pairedDevices)
{
addDevice( device );
}
}
return true;
}
public String connectToDevice(final BluetoothDevice device)
{
if ( mDevice != null )
disconnectDevice();
if( mBluetoothAdapter == null || myActivity == null )
return "System not initialized or bluetooth not active";
if ( device.getBondState() != BluetoothDevice.BOND_BONDED )
{
// TODO: find a way to do a synchronized bounding operation
return "Device is not bonded";
}
final boolean[] the_result = new boolean[1];
the_result[0] = false;
final Semaphore mutex = new Semaphore(0);
Runnable connectRunnable = new Runnable() {
@Override
public void run() {
UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
try
{
mSocket = device.createInsecureRfcommSocketToServiceRecord( MY_UUID );
System.out.println("Created RFcomm socket");
mSocket.connect();
if ( mSocket.isConnected() )
{
System.out.println("Connected RFcomm socket");
mOutputStream = mSocket.getOutputStream();
mInputStream = mSocket.getInputStream();
System.out.println("Retrieved output stream");
the_result[0] = true;
}
else
{
System.out.println("Failed to connect RFcomm socket");
}
}
catch (IOException e)
{
System.out.println("Failed to open RFcomm socket (createRfcommSocketToServiceRecord)");
System.out.println(e.toString());
}
mutex.release();
}
};
myActivity.runOnUiThread( connectRunnable );
// waiting for thread to be completed...
try {
mutex.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
if ( the_result[0] )
{
System.out.println("Connection succeeded");
return "";
}
else
{
System.out.println("Connection failed");
return "Failed to connect device";
}
}
/* Request to disconnect the device */
public boolean disconnectDevice(){
System.out.println("Disconnecting device...");
if ( mSocket != null )
{
// block read/write
mOutputStream = null;
mInputStream = null;
try
{
mSocket.close();
}
catch( IOException e )
{
e.printStackTrace();
return false;
}
mSocket = null;
}
mDevice = null;
return true;
}
/* Send bytes to the connected device */
public boolean writeData( byte[] buffer )
{
if( mOutputStream == null )
{
System.out.println("No connection, can't send data");
}
else
{
try
{
mOutputStream.write( buffer );
return true;
}
catch (IOException e)
{
System.out.println( "Failed to send data" );
e.printStackTrace();
}
}
return false;
}
public static String byteArrayToHex(byte[] a, int size) {
StringBuilder sb = new StringBuilder(size * 5);
for( int i = 0; i != size; ++i )
sb.append(String.format("0x%02x ", a[i] & 0xff));
return sb.toString();
}
public int getBytesPending()
{
try
{
return mInputStream.available();
}
catch (IOException e)
{
return 0;
}
}
/* Non blocking read function. Read bytes from the connected device.
* Return number of bytes read
* return 0 if not enough bytes available
* return -1 in case of error
*/
public int readData( byte[] buffer, int size, boolean blocking )
{
if ( mInputStream == null )
{
System.out.println("No connection, can't receive data");
}
else
{
try
{
final boolean verbose = false;
if ( blocking )
{
if ( verbose )
System.out.println( "Blocking request of " + buffer.length + " byte(s)" );
int res = 0;
int temp = 0;
while ( true )
{
temp = mInputStream.read( buffer, res, size - res );
res += temp;
if ( res >= size )
{
break;
}
else
{
if ( verbose )
System.out.println( "Received " + res + " byte(s) to far : " + byteArrayToHex(buffer,size) );
}
try {
Thread.sleep(10);
} catch(InterruptedException ex) {
}
}
if ( verbose )
System.out.println( "Received " + res + " byte(s) : " + byteArrayToHex(buffer,size) );
return res;
}
else
{
int available = mInputStream.available();
if ( verbose && available != 0 )
{
Calendar c = Calendar.getInstance();
Date date = new Date();
c.setTime(date);
c.get(Calendar.MILLISECOND);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentTime = sdf.format(date);
System.out.println( currentTime + ":" + c.get(Calendar.MILLISECOND) + " - " + available + " bytes available, requested " + buffer.length );
}
if ( available >= size )
{
int res = mInputStream.read( buffer, 0, size ); // only call read if we know it's not blocking
if ( verbose )
System.out.println( "Received " + res + " byte(s) : " + byteArrayToHex(buffer,size) );
return res;
}
else
{
return 0;
}
}
}
catch (IOException e)
{
System.out.println( "Failed to read data...disconnected?" );
//e.printStackTrace();
}
}
return -1;
}
public byte[] readNextFrame( boolean blocking )
{
if ( readData( mHeader, mHeader.length, blocking ) == mHeader.length )
{
int size = mHeader[2];
if ( size < 0 )
size = -size;
if ( readData( mFrame, size, blocking ) == size )
{
byte[] res = new byte[mHeader.length + size];
System.arraycopy(mHeader, 0, res, 0, mHeader.length);
System.arraycopy(mFrame, 0, res, mHeader.length, size);
return res;
}
}
return null;
}
*/ read frame but without allocating any memory, does not retur condumed bytes */
public boolean eatNextFrame( boolean blocking )
{
if ( readData( mHeader, mHeader.length, blocking ) == mHeader.length )
{
int size = mHeader[2];
if ( size < 0 )
size = -size;
if ( readData( mFrame, size, blocking ) == size )
{
return true;
}
}
return false;
}
public boolean startECG()
{
// some code sending instructions to configure my device
}
}
主 Java 文件,连接并进行 10 秒采集:
// Here is the code for Medoc:
BluetoothHelper helper = new BluetoothHelper(this);
String error = helper.initializeBluetooth();
if ( error.isEmpty() )
{
if ( helper.addPairedDevices( ) )
{
if ( !helper.getDevices().isEmpty() )
{
if ( helper.getDevices().size() == 1 )
{
BluetoothDevice device = helper.getDevices().firstElement();
error = helper.connectToDevice( device );
if ( error.isEmpty() )
{
if ( helper.startECG() )
{
// acquiere data for 10 seconds
Date start = new Date();
Date end = new Date();
Date empty = null;
int lastMinute = 0;
int maxBufferSize = 0;
boolean receivedData = false;
while ( end.getTime() - start.getTime() < 10 * 1000 )
{
int currentMinute = (int) (( end.getTime() - start.getTime() ) / 1000);
if ( currentMinute != lastMinute )
{
if ( receivedData )
System.out.println( "During second #" + lastMinute + " max buffer size was : " + maxBufferSize );
else
System.out.println( "During second #" + lastMinute + " no data was received!" );
maxBufferSize = 0;
receivedData = false;
lastMinute = currentMinute;
}
if ( helper.eatNextFrame(false) )
{
receivedData = true;
}
if ( helper.getBytesPending() == 0 )
{
if ( empty == null )
{
empty = new Date();
}
}
else
{
if ( empty != null )
{
Date now = new Date();
int elapsed = (int) ( now.getTime() - empty.getTime() );
if ( elapsed > 100 )
System.out.println( "No pending data, during " + elapsed + "ms" );
empty = null;
}
}
maxBufferSize = Math.max( helper.getBytesPending(), maxBufferSize );
end = new Date();
}
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
dlgAlert.setMessage( "Done" );
dlgAlert.setPositiveButton("Ok",null);
dlgAlert.create().show();
}
else
{
error = "Failed to start ECG";
}
helper.disconnectDevice();
}
}
else
{
error = "Too many devices found";
}
}
else
{
error = "No device found";
}
}
else
{
error = "Failed to scan for devices";
}
}
if ( !error.isEmpty() )
{
AlertDialog.Builder dlgAlert2 = new AlertDialog.Builder(this);
dlgAlert2.setMessage( error );
dlgAlert2.setPositiveButton("Ok",null);
dlgAlert2.create().show();
}
这里是程序的输出:
12-01 14:12:51.755: I/System.out(15940): During second #0 max buffer size was : 63
12-01 14:12:52.755: I/System.out(15940): During second #1 max buffer size was : 133
12-01 14:12:53.755: I/System.out(15940): During second #2 max buffer size was : 66
12-01 14:12:54.755: I/System.out(15940): During second #3 max buffer size was : 61
12-01 14:12:55.755: I/System.out(15940): During second #4 max buffer size was : 129
12-01 14:12:56.705: I/System.out(15940): No pending data, during 501ms
12-01 14:12:56.755: I/System.out(15940): During second #5 max buffer size was : 939
12-01 14:12:57.755: I/System.out(15940): During second #6 max buffer size was : 980
12-01 14:12:58.755: I/System.out(15940): During second #7 max buffer size was : 1008
12-01 14:12:59.195: I/System.out(15940): No pending data, during 488ms
12-01 14:12:59.695: I/System.out(15940): No pending data, during 489ms
12-01 14:12:59.755: I/System.out(15940): During second #8 max buffer size was : 990
12-01 14:13:00.185: I/System.out(15940): No pending data, during 490ms
12-01 14:13:01.205: I/System.out(15940): Disconnecting device...
如您所见,在前 5 秒内,读取缓冲区仍然非常小,并且缓冲区空的时间不会超过 100 毫秒(请参阅输出“无待处理数据”的代码)。然后,从第五秒开始我们:
在数据采集的前 5 秒之后,就好像数据在某处被缓冲,并且可以以约 500 毫秒的 block 在 InputStream 中读取......
有时,情况可能更糟,5 秒后根本没有接收到数据:
12-01 14:35:54.595: I/System.out(16386): During second #0 max buffer size was : 22
12-01 14:35:55.595: I/System.out(16386): During second #1 max buffer size was : 93
12-01 14:35:56.595: I/System.out(16386): During second #2 max buffer size was : 108
12-01 14:35:57.595: I/System.out(16386): During second #3 max buffer size was : 61
12-01 14:35:58.595: I/System.out(16386): During second #4 max buffer size was : 64
12-01 14:35:59.595: I/System.out(16386): During second #5 max buffer size was : 63
12-01 14:36:00.595: I/System.out(16386): During second #6 no data was received!
12-01 14:36:01.595: I/System.out(16386): During second #7 no data was received!
12-01 14:36:02.595: I/System.out(16386): During second #8 no data was received!
注意:我尝试在创建 BluetoothHelper
和调用 startECG()
之前 hibernate 几秒钟。相同的行为(采集速度减慢或在 5 秒后停止)。
编辑:我正在经历:
但在带有自定义 CyanogenMod 11 Android 4.4.2 的 Galaxy S3 上则不然:数据流看起来很完美,5 秒后没有卡住,数据实时到达...
编辑 12 月 15 日:
按照提议,将阅读移动到一个单独的线程:使 BluetoothHelper
实现 Runnable
并将这些方法/属性添加到类中:
private int mFramesReceived;
private long mLongestPause;
public void clearReceived()
{
mFramesReceived = 0;
mLongestPause = 0;
}
public int received()
{
return mFramesReceived;
}
public long longestPause()
{
return mLongestPause;
}
@Override
public void run() {
System.out.println( "Started thread" );
int lastSeconde = 0;
long currentTimeMillis = System.currentTimeMillis();
long started = System.currentTimeMillis();
// Keep listening to the InputStream until an exception occurs
while (true) {
if ( eatNextFrame( true ) )
{
//System.out.println( "Got some data" );
mLongestPause = Math.max( mLongestPause, System.currentTimeMillis() - currentTimeMillis );
currentTimeMillis = System.currentTimeMillis();
mFramesReceived++;
int currentSeconde = (int) (( System.currentTimeMillis() - started ) / 1000);
if ( currentSeconde != lastSeconde )
{
if ( mFramesReceived != 0 )
System.out.println( "During second #" + lastSeconde + " max pause was : " + mLongestPause );
else
System.out.println( "During second #" + lastSeconde + " no data was received!" );
clearReceived();
lastSeconde = currentSeconde;
}
}
else
{
System.out.println( "Failed to get some data, connection closed?" );
break;
}
}
}
然后将调用者更改为:
if ( helper.startECG() )
{
new Thread(helper).start();
try {
Thread.sleep(10000); // wait 10 seconds
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
dlgAlert.setMessage( "Done" );
dlgAlert.setPositiveButton("Ok",null);
dlgAlert.create().show();
}
else
{
error = "Failed to start ECG";
}
helper.disconnectDevice();
并没有解决问题,这是输出:
During second #0 max pause was : 48
During second #1 max pause was : 45
During second #2 max pause was : 33
During second #3 max pause was : 35
During second #4 max pause was : 58
During second #5 max pause was : 498
During second #6 max pause was : 477
During second #7 max pause was : 480
During second #8 max pause was : 986
During second #9 max pause was : 497
最佳答案
此问题显然与报告的问题相似 here .
5 秒后,要么连接断开,要么实时流式传输速度急剧下降。
如前所述here Android >4.3 显然不喜欢超过 5 秒的单向通信。所以我现在每 1 秒向设备发送一个虚拟命令(一种“保持 Activity ”命令)现在 Android 很高兴,因为它不再是单向通信......所以数据流在之后也一样好第五秒!
关于java - Android 上的实时蓝牙 SPP 数据流只能工作 5 秒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27229813/
我已经使用基于 RFCOMM 和串行端口配置文件 (SPP) 的 MS 蓝牙套接字在我的 PC 和蓝牙设备之间建立了连接。 连续接收数据没有问题。但是,如果要发送一个字节(作为命令),设备不会接收到它
我们正在开发一款通过蓝牙使用 SPP(串行端口配置文件)的应用程序,开发人员正在讨论使用某种类型的协议(protocol)和数据包传输,还是仅在没有任何形式的 ACK、序列或大小信息的情况下流式传输数
我目前正在尝试构建一个库,以便在通用应用程序上使用串行端口配置文件 (SPP)。 据我所知,SPP 在 RFCOMM 之上运行。 RFCOMM 的基础知识在 MSDN 中进行了概述,这很好。我还能够“
如何通过蓝牙串行端口配置文件将数据从一台Mac发送到另一台Mac 情境 我正在寻找一种通过蓝牙将串行数据从一台Mac发送到另一台Mac的方法。串行通信已集成到许多创意编码平台(MaxMSP,Proce
我是 Android 开发的新手,除了无线连接两个设备外,我对蓝牙的真正工作原理一无所知。我一直在使用 BluetoothChat 示例,以及我购买的 Android 书籍中的示例。它们看起来非常相似
我有一个 SPP 蓝牙应用程序,问题出在这种情况下。android 设备已连接到蓝牙扬声器,当我尝试连接到我的 SPP Micro 设备时,出于同样的原因,蓝牙已连接。 我如何断开蓝牙扬声器与我的应用
不好意思 friend 打扰了。我是全职妈妈,是 Android 开发的新手,我把我们当作兼职工作。我有 Java 开发经验。 我试着查看那个蓝牙聊天示例,并在这里搜索了很多关于从哪里开始的信息。当我
我想开发一个 ios 应用程序,通过蓝牙 SPP 与另一个支持蓝牙的设备进行通信。 iOS 是否支持 SPP? 我检查了 iOS 支持的配置文件,但看不到有关 SPP 的任何信息.. http://s
我正在尝试使用 SPP 通过蓝牙(在 Java 中,使用 BlueCove API)在两台 PC 之间传输文件(MP3 大小约为 6 兆字节)。我可以使文件传输在一个方向上正常工作(例如,一个文件从客
我有一个带有板载蓝牙功能的嵌入式板。我的开发板运行 Linux,BlueZ 堆栈提供蓝牙支持。我可以访问所有 bluez 实用程序,例如 hciconfig、sdptool、rfcomm 等。 我需要
我有一个定制的蓝牙设备,我可以使用 Windows 10 与之配对和连接,它创建了 2 个 com 端口 - 一个列为传入端口,一个列为传出端口。 当我使用 32Feet C# 蓝牙库连接时,我能够发
我需要使用蓝牙 SPP 以 1.15k 的速率从远程蓝牙设备收集蓝牙数据。我按如下方式连接到远程设备。 try { tmp = device.createRfcommSocketToService
我有一些连接到 Android 手机的蓝牙设备,但我无法检测到断开连接。除非需要,否则蓝牙设备不会发送数据包,因此不能选择在数据包接收时使用看门狗来检测断开连接。我读过您可以使用 ACLDisconn
我们即将发布我们软件的新版本,对于之后的版本,我们的目标是使我们的蓝牙 SPP 连接的连接过程更加可靠。我们在我们的产品中使用 RN42 模块,目前,有时可能需要多次尝试才能连接到我们的电路板。 这是
我是 Android 编程的新手,现在遇到了一个问题。我想将我的 android 手机用作蓝牙服务器,这意味着当我打开一个特殊的 Activity 时,手机应该监听其他蓝牙设备(已经配对)并且其他设备
有人有 iOS 的 SPP 通信(蓝牙串口)示例代码吗?我需要在我的微芯片图片和 iphone 或 iPod 之间进行通信。 我知道我需要一个经过批准的苹果蓝牙 rs232BT 加密狗,我也有一些带有
我在尝试在我的项目中使用蓝牙时遇到问题。在以前的版本中,我使用 HC-05 蓝牙模块,它在连接任何设备后立即为我提供一个简单的串行连接。现在项目发展了,我们选择使用 SIM800H,因为它为我们提供了
我有一个相当简单的程序,主要基于此处发布的简单蓝牙测试客户端应用程序: http://www.anddev.org/code-snippets-for-android-f33/serial-over-
所以我在eclipse (API8) 上编译并成功运行了Android Bluetooth Chat 项目。 问题是,当我连接到我自己的嵌入式蓝牙设备 (http://www.sparkfun.com
我有一个使用蓝牙 SPP (RFCOMM) 与硬件通信的应用程序。该应用程序和蓝牙连接效果很好。问题是当另一个应用程序启动时也使用 SPP,然后其中一个应用程序停止。一旦任何一个应用程序停止,无论是通
我是一名优秀的程序员,十分优秀!