How to read all bytes together via Bluetooth?
Asked Answered
C

6

12

I have an application that uses the bluetooth to receive some data (bytes) from other device. everything is going well, but I have a small issue on receiving the bytes all together. After receiving the bytes I show them on a Toast just to test them. When the other device sends 10 bytes together (for example: "ABCDEFGHIJ"), the program will take the first byte "A" only and show it on a Toast, then go to the second iteration and read the other 9 bytes and show "BCDEFGHIJ" on the Toast. Here is my code:

byte[] buffer = new byte[1024]; // Read 1K character at a time.
int bytes = 0; // Number of bytes.

while(true)
{
    try
    {
        // Read from the InputStream.
        bytes = bInStream.read(buffer);

        // Send the obtained bytes to the MainActivity.
        mainActivityHandler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
    }
    catch(IOException e)
    {
        connectionLost();
        break;
    }
}

In the MainActivity, I have:

// The Handler that gets information back from the BluetoothManager.
private final Handler handler = new Handler()
{
    @Override
    public void handleMessage(Message msg)
    {
        switch(msg.what)
        {
            case MESSAGE_READ:
                byte[] readBuf = (byte[]) msg.obj;

                // construct a string from the valid bytes in the buffer.
                String readMessage = new String(readBuf, 0, msg.arg1);
                Toast.makeText(MainActivity.this, readMessage, Toast.LENGTH_SHORT).show();
                break;

            // ...
        }
    }
};

How can I receive all the bytes together?!

Continuo answered 10/2, 2012 at 16:56 Comment(2)
Can I see how you're sending your messages? Are you doing something like bOutStream.write("ABCDEFGHIJ".getBytes()) or are you writing out characters one at a time?Fulgurous
A bluetooth module is attached to arduino, so I'm using the serial monitor of the arduino software to send the message.Continuo
F
7

Mmm most likely the culprit is in the way you're sending the messages. Your receive has no problems, it will receive as many bytes (up to your 1024) as it is written to.

If you have no control over the way the messages are sent you can probably read one byte at a time and then send a handler message you when you hit a predefined terminator. Ex: "ABCDEFGHIJ#" where # is the terminator.

String msg = "";
byte ch;
while((ch=mInStream.read())!='#') {
    bytes++;
    msg+=ch;
}
Fulgurous answered 10/2, 2012 at 17:36 Comment(2)
+1 Good solution. I will use this solution till I find another way to fix the problem. Thanks!Continuo
What if I transfer binary data? How can I be sure that the terminator is not part of the data stream?Disquisition
F
6

The bluetooth connection is stream based, not packet based. There is no guarantee or attempt to preserve packetization. So any number of writes can result in any number of reads, just the stream of bytes are guaranteed to be correct. If you need to detect packets, you need to provide your own packet structure to wrap your data. For example, add a length field before each data packet so you can reconstruct on the receiving side.

Feet answered 10/2, 2012 at 18:36 Comment(2)
@Feet And how do I know the length of the length field?Disquisition
@Feet Do you have any proof/documentation that Android can't preserve packetisation, or re-form the packets itself? Only asking as, in an app I'm developing at the moment, it does sometimes, and other times it doesn't so just trying to figure out why!Zahavi
R
5

The accepted answer from @broody is correct. But if the data itself contains '#', it might be difficult to fetch the data. So the best approach according to me is appending '\n' followed by '\r' (or any other characters which are unlikely to feature as data Refer ASCII Table) in the Device which sends data to your Android app. It just acts as Line feed and marks end of data.

Eg: ABCDEFGH\n\r

Then your code can be something like this :

byte[] buffer = new byte[1024];
 while (true) {

         // Read from the InputStream
          buffer[bytes] = (byte) mmInStream.read();                 
         // Send the obtained bytes to the UI Activity
 if ((buffer[bytes] == '\n')||(buffer[bytes]=='\r'))
 {
   mHandler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
   bytes=0;
 }
 else
 bytes++;
}

Hope it helps Regards

Russia answered 29/11, 2014 at 8:8 Comment(1)
Brilliant! That solved my issue, without adding the extra # character on the Arduino side. I simply skipped the check for the \r (I only check for \n), and it works like a charm.Nicolina
S
1

To read all bytes together you need to separate the data by "\n" or "\r" or "\r\n" in your code..

For example: If you want to send data from Arduino to Android app via Bluetooth:

(Arduino code):

    int count =0;
    int sensorPin = 0;

    void setup()
    {
      Serial.begin(9600);
    }

    void loop()
    {
    int val= analogRead(sensorPin);
      if(val<threshold){ 
         a++; 
      }
      else{
        delay(2);
        count = count + 1;
        Serial.print(count);
        Serial.print("\n");
          }

And now, to read the sent data (value of variable 'count'), here is the code of Android Studio:

 private class ConnectedThread extends Thread {
        private final InputStream mmInStream;

        public ConnectedThread(BluetoothSocket socket) {
            InputStream tmpIn = null;

            // Get the input streams, using temp objects because
            // member streams are final
            try {
                tmpIn = socket.getInputStream(); // opens the input stream in order to retrieve InputStream objects
            } catch (IOException e) {
            }

            mmInStream = tmpIn;
        }

     public void run() {
        int bytes; // bytes returned from read()
        int availableBytes = 0;

        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                availableBytes = mmInStream.available();
                if(availableBytes>0){
                    byte[] buffer = new byte[availableBytes];  // buffer store for the stream
                    // Read from InputStream
                    bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
                    if (bytes>0){
                        h.obtainMessage(RECEIVE_MESSAGE, bytes, -1, buffer).sendToTarget();     // Send to message queue Handler
                    }
                   }
                } catch (IOException e) {
                break;
                        }
        }
    }

And this:(in onCreate() method):

mConnectedThread = new ConnectedThread(btSocket);
mConnectedThread.start();
// The Handler that gets information back
 h = new Handler() { // Handler-->used to communicate b/w UI & BG Thread
            public void handleMessage(android.os.Message msg) {
                switch (msg.what) {
                    case RECEIVE_MESSAGE:// if receive message
                        byte[] readBuf = (byte[]) msg.obj;
                       String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array

                        sb.append(strIncom);                                                // append string
                        int endOfLineIndex = sb.indexOf("\n");                            // determine the end-of-line
                        if (endOfLineIndex > 0) {                                            // if end-of-line,
                            String sbprint = sb.substring(0, endOfLineIndex);               // extract string
                            sb.delete(0, sb.length());// and clear
                            Toast.makeText(ledControl.this,sbprint,Toast.LENGTH_SHORT).show();
                            footSteps.setText(sbprint);            // update TextView
                        }
                        break;
                }}};
Sidhu answered 2/4, 2018 at 17:44 Comment(0)
E
0

None of the above answers worked for me . Thread.sleep(1000) gave me the solution

Equi answered 17/10, 2018 at 4:44 Comment(0)
Q
-1

A way to handle longer-than-buffer messages (can be dangerous because can take up your memory if never cleared) is to handle them in chunks:

String inString = "";
byte[] buffer = new byte[1024];  // buffer store for the stream
int bytes; // bytes returned from read()

while (true) {
    try {
        bytes = mmInStream.read(buffer);
        String chunk = new String(buffer, 0, bytes);
        if(chunk.contains(";"))
        {
            inString += chunk.substring(0,chunk.indexOf(';'));
            Message msg = new Message();
            msg.obj  = inString;
            handler.sendMessage(msg);
            inString =  chunk.substring(chunk.indexOf(';'));
        }
        else
        {
            inString += chunk;
        }
    } catch (IOException e) {
        break;
    }
}
Quant answered 20/5, 2014 at 17:59 Comment(1)
the code assumes ';' is the message delimiter. the code is an example implementation, and is not universal - you can not copy-paste it and expect to work without modification, but is showing a concept behind. and it reads all messages. once the message end is reached, handler.sendMessage(msg); is called to handle the complete message, and processing the buffer continues. You must implement the handler to process/read the messages. that is the conceptQuant

© 2022 - 2024 — McMap. All rights reserved.