Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error in reading data from InputStream in Bluetooth on Android

I'm working on an Android app, which uses bluetooth connection to transfer data between my android smartphone and a non-android bluetooth module, using SPP profile. I've used Bluetooth Chat Example from Android Developer site as reference.

I've successfully made two devices connect to each other and sent simple strings from the smart phone to the bluetooth module. But I've got some error in reading data sent back from the module. I've used the following code, which is exactly the same as in Bluetooth Chat Example, to read data from InputStream

while (true) {
    try {
        // Read from the InputStream
        bytes = mmInStream.read(buffer);
        String str = new String(buffer);
        Log.i(TAG, "mmInStream - " + str);
        // Send the obtained bytes to the UI Activity
        mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
                .sendToTarget();
    } catch (IOException e) {
        Log.e(TAG, "disconnected", e);
        connectionLost();
        break;
    }
}

When my bluetooth module send a simple string to the phone, that string is not received correctly. It is splited into several pieces in random ways. For example, if I send "1234567890abcdef1234567890abcdef0123456789" for three times to the phone, the Logcat on Eclipse will log these:

mmInstream - 12345678910abcdef��������(continuing null)
mmInstream - 1��������(continuing null)
mmInstream - 2345678910abcdef0123456789��������(continuing null)

for the first time. In the second and the third time data is transmitted, it is received in a difference pieces:

mmInstream - 1234567891�������(continuing null)
mmInstream - 0abcdef012�������(continuing null)
mmInstream - 3456789���������(continuing null)

mmInstream - 1234567891����������������(continuing null)
mmInstream - 0abcdef0123456789������������(continuing null)

I don't know why this happen and how to solve this problem. If data is received in a arbitrary way like this, I can't get necessary data to process. How can I get it in one pieces?

Any help would be appreciated.

Many Thanks.

like image 748
theman Avatar asked Sep 06 '12 07:09

theman


3 Answers

Two things I noticed with your code:

  • First of all sending further down to your app a reference to the buffer in which you read is not always a good solution: What if in the meantime the buffer gets overridden? See this bug on stackoverflow for example You can bypass this by making a copy of the data (for example use buffer.clone()) which you have read from Bluetooth, or if you don't like using too much memory you can make your read buffer a circular one.

  • You should be able to recompile your data even if it is received in separate packets (but packets are received in a short time span). You can make start/stop flags for instance. Ofc it still depends on the type of object you send over Bluetooth...

And now a possible solution if the 2 previous warnings are of no use is this:

Instead of an infinite loop which calls .read - a blocking call - you can do something like this:

while(true) {
     if mmInStream.getAvailable()>0 { 
          -your read code here-
     }
     else SystemClock.sleep(100);
}

It's a hack and it might still sometimes read only some part of the message - but it will be very rare!

Pls vote up/correct if useful!

like image 88
Radu Avatar answered Oct 21 '22 15:10

Radu


I have a this problem and I've solved the problem of this characters � in this way

public void run() {        
    int bytes; // bytes returned from read()
    int availableBytes = 0;        
    // Keep listening to the InputStream until an exception occurs
    while (needRun) {
        try {
            availableBytes = mmInStream.available();
            if(availableBytes > 0){
                byte[] buffer = new byte[availableBytes];  // buffer store for the stream
                // Read from the InputStream


                bytes = mmInStream.read(buffer);
                Log.d("mmInStream.read(buffer);", new String(buffer));
                if( bytes > 0 ){                        
                    // Send the obtained bytes to the UI activity
                    mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();                     
                }                                   
            }
        } catch (IOException e) {
            Log.d("Error reading", e.getMessage());
            e.printStackTrace();
            break;
        }
    }
}
like image 30
papucho Avatar answered Oct 21 '22 15:10

papucho


Radu's fix works fantastic!. I myself have been working on this issue for quite some time now using the Bluetooth Chat sample code. Below is what i'm using to capture and display temperature reading from a remote sensor:

  // Keep listening to the InputStream while connected
        while (true) {

             try {
                 byte[] buffer = new byte[128];
                 String readMessage;
                 int bytes;
                if (mmInStream.available()>2) { 
                    try {
                       // Read from the InputStream
                        bytes = mmInStream.read(buffer); 
                        readMessage = new String(buffer, 0, bytes);

                       }catch (IOException e) {
                        Log.e(TAG, "disconnected", e);
                        break;
                    }
                     // Send the obtained bytes to the UI Activity
                     mHandler.obtainMessage(HomeBlueRemote.MESSAGE_READ, bytes, -1, readMessage)
                          .sendToTarget();
        }
        else {
            SystemClock.sleep(100);
               }
            } catch (IOException e) {

                e.printStackTrace();
            }

       }

    }

As u see, I modified the (buffer.available() > 0) to > 2. This is because the my micro-controller is sending 2 bytes for the temperature. . Prior to this fix, inputstream for the byte count would vary, sometimes only capturing 1 byte which messed up the temperature display reading in the Android app. Again, out all the suggestions on the web, Radu has the best workaround for the android inputstream bug.

like image 1
Ryan Harris Avatar answered Oct 21 '22 15:10

Ryan Harris