Android蓝牙InputStream实时读取

时间:2014-08-15 16:25:54

标签: android bluetooth inputstream

我正在开发一个Android应用程序,它通过蓝牙接收实时数据并将其绘制在屏幕上。

数据是陀螺仪传感器位置信息。我是从定制的Freescale Kinetis K10微控制器板(由我自己设计和测试)发送的。对于蓝牙通信,我使用的是HC-05蓝牙模块。

数据格式如下:

byte_1:位置标识字节,始终等于-128

byte_2:轴1的位置

byte_3:轴2的位置

byte_4:轴3的位置

我按照特定的顺序一个接一个地连续发送这4个字节。我每隔5毫秒发送一个4字节的数据包,发送数据包大约需要4.7毫秒(9600波特率)。 微控制器输出的数据在精度和时序方面是完美的(用逻辑分析仪检查)。

问题在于,当从手机接收时,一些字节似乎丢失了。这是代码的一部分,我在这里阅读InputStream:

private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            Log.e("Printer Service", "temp sockets not created", e);
        }
        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    @Override
    public void run() {

        Log.i("BluetoothService", "BEGIN mConnectedThread");
        byte[] buffer = new byte[4];
        int bytes;

        while (true) {

                try {

                    bytes = mmInStream.read(buffer);

                    int position = 0;

                    if(buffer[0] == -128) {
                        if(bytes >= 2) {
                            sendArray.errorTilt = buffer[1];
                        }
                        if(bytes >= 3) {
                            sendArray.errorRoll = buffer[2];
                        }
                        if(bytes == 4) {
                            sendArray.errorPan = buffer[3];
                        }
                    }
                    else if(buffer[1] == -128) {
                        position = 1;
                        if(bytes >= 3) {
                            sendArray.errorTilt = buffer[2];
                        }
                        if(bytes == 4) {
                            sendArray.errorRoll = buffer[3];
                        }
                        if(bytes >= 2) {
                            sendArray.errorPan = buffer[0];
                        }
                    }
                    else if(buffer[2] == -128 && bytes >= 3) {
                        position = 2;
                        sendArray.errorRoll = buffer[0];
                        sendArray.errorPan = buffer[1];
                        if(bytes == 4) {
                            sendArray.errorTilt = buffer[3];
                        }
                    }
                    else if(buffer[3] == -128 && bytes == 4) {
                        position = 3;
                        sendArray.errorTilt = buffer[0];
                        sendArray.errorRoll = buffer[1];
                        sendArray.errorPan = buffer[2];
                    }

                    if(position <= bytes && bytes > 1) {
                        sendArray.errorUpdate = true;
                    }

                } catch (Exception e) {

                    e.printStackTrace();
                    connectionLost();
                    BluetoothService.this.stop();
                    break;
                }
        }
    }


    public void write(int oneByte) {
        try {
            mmOutStream.write(oneByte);

        } catch (IOException e) {
            Log.e("BluetoothService", "Exception during write", e);
        }
    }

    public void cancel() {
        try {
            mmSocket.close();

        } catch (IOException e) {
            Log.e("BluetoothService", "close() of connect socket failed", e);
        }
    }
}

sendArray是一个保留许多不同变量的单例。

errorTilt,errorRoll和errorPan是轴的当前值,它们正在从接收缓冲区更新。

&#34;位置&#34;保持位置识别字节的位置。它用于检查是否已更新任何变量。

很多时候输入缓冲区只收到一个字节,因为我不知道应该是哪个轴,因为我没有关于它的相对位置的信息。位置字节,这个特殊的字节是无用的,并且会丢失。

我通过以下方法测试了接收的准确性。我在其中一个轴上输出了一个三角波,而不是轴数据。在电话中,三角波的线条不应该是直的,而是随机弯曲并包含伪影。

为了绘制我正在使用GraphView的数据,我正在从一个单独的线程中以相等的间隔更新图形。

我尝试使用较长的接收缓冲区(使用修改后的接收算法),但这并不会有帮助,因为一次只能接收几个字节。

我尝试过实现InputStream.available()但它总是提供127个字节,这似乎不是真的。

我已经阅读了很多关于类似问题的帖子,我花了最近5天的时间来处理它,但我找不到一个好的解决方案。

总而言之,我需要实现准确,实时(或接近实时)接收所有字节。

有类似问题的主题: How to do good real-time data streaming using Java Android SDK

谢谢。

更新:

我尝试仅为其中一个轴发送信息,因此它简单明了,无需位置字节​​。我每5毫秒再次发送一次,但这次连续字节之间的时间更长,因为它只是数据包中的一个字节。

这次我使用了InputStream.read(),它不需要缓冲区。但是,传入的数据再次被破坏,因为无法接收随机字节。

我已成功使用此方法看到不同的项目,我不知道为什么它不与我合作。我认为这可能是我使用的HC-05蓝牙模块的一个问题,但我尝试了另一个 - HC-06,情况是一样的。我没有尝试过不同的手机,但我的手机(三星Galaxy S3,Android 4.1.2)似乎工作正常。

UPDATE2:在尝试从流中读取之前,我再次尝试使用InputStream.available()测试原始代码。

当条件可用()> 0时,没有重大变化,可能会稍微恶化。 当条件可用()> 1时,它永远不会读取。我想这是因为不可靠的available()方法,正如文档中所述。

1 个答案:

答案 0 :(得分:0)

如果您想从微控制器板获取数据,那么

您的数据处理不正确。你必须使用bytesAvaliable,因为android蓝牙套接字在蓝牙微控制器板上相当慢。但是“bytesAvaliable方式”有细微差别 - 由于套接字是慢速接收器,bytesAvaliable可以一次从板上捕获超过1个数据包所以你必须自己发送readed数据,请在下面检查我的代码!我的代码从惯性传感器获取38个字节的数据包,所以你只需要改变字节数! 0xAA是每个下一个数据包的第一个字节,因此如果找到0xAA字节并且有38个字节,则会得到数据包并使迭代器无效。但无论如何,我确信你有时会丢失数据,因为它不是高频数据传输方式 的

public void run() {
            byte[] bytes = new byte[38];
            int iterator = 0;
            while (true) {

                try {
                    int bytesAvailable = mmInStream.available();
                    if (bytesAvailable > 0) {
                        byte[] curBuf = new byte[bytesAvailable];
                        mmInStream.read(curBuf);
                        for (byte b : curBuf) {
                            if (b == (byte) 0xAA && iterator == 38) {
                                mHandler.obtainMessage(MainActivity.DATA_READ, bytes.length, -1, bytes).sendToTarget();
                                iterator = 0;
                                bytes[iterator] = b;
                            } else {
                                    bytes[iterator] = b;
                            }
                            iterator++;
                        }
                    }
                } catch (IOException ex) {
                    Log.e(TAG, "disconnected", ex);

                    connectionLost();
                    break;
                }
            }
}