简体   繁体   中英

Android Bluetooth Read InputStream

I'm trying to read serial data sent from an external bluetooth module to my HTC Sensation but when I call InputStream.available() - it returns 0 so I can't iterate over the bytes recieved and call InputStream.read(byteArray).

Could somebody help me solve this problem?

Do I need to check for available bytes before reading them?

I apologise for my technically inacurrate post.

Here's my code:

public class BluetoothTest extends Activity
{
TextView myLabel;
TextView snapText;
EditText myTextbox;
BluetoothAdapter mBluetoothAdapter;
BluetoothSocket mmSocket;
BluetoothDevice mmDevice;
OutputStream mmOutputStream;
InputStream mmInputStream;
Thread workerThread;
byte[] readBuffer;
int readBufferPosition;
int counter;
volatile boolean stopWorker;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button openButton = (Button)findViewById(R.id.open);
    Button closeButton = (Button)findViewById(R.id.close);

    Button chkCommsButton  = (Button)findViewById(R.id.chkCommsButton);
    Button offButton = (Button)findViewById(R.id.offButton);

    myLabel = (TextView)findViewById(R.id.mylabel);
    snapText = (TextView)findViewById(R.id.snapText);


    //Open Bluetooth
    openButton.setOnClickListener(new View.OnClickListener()
    {
        public void onClick(View v)
        {
            try 
            {
                findBT();
                openBT();
            }
            catch (IOException ex) { }
        }
    });

    //Close Bluetooth
    closeButton.setOnClickListener(new View.OnClickListener()
    {
        public void onClick(View v)
        {
            try 
            {
                closeBT();
            }
            catch (IOException ex) { }
        }
    });


    // Check Comms     - multicast all SNAP nodes and pulse their  BLUE led
     chkCommsButton.setOnClickListener(new View.OnClickListener() {

        public void onClick(View v) {
            try {
                chkcommsButton();
            } catch (Exception e) {
                // TODO: handle exception
            }

        }
    });

  //Off Button    - set strip to all OFF
    offButton.setOnClickListener(new View.OnClickListener() {

        public void onClick(View v) {
            try {
                offButton();
            } catch (Exception e) {
                // TODO: handle exception
            }

        }
    });


}


void findBT()
{
    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if(mBluetoothAdapter == null)
    {
        myLabel.setText("No bluetooth adapter available");
    }

    if(!mBluetoothAdapter.isEnabled())
    {
        Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBluetooth, 0);
    }

    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
    if(pairedDevices.size() > 0)
    {
        for(BluetoothDevice device : pairedDevices)
        {
            if(device.getName().equals("BTNODE25"))    // Change to match RN42 - node name
            {
                mmDevice = device;
                Log.d("ArduinoBT", "findBT found device named " + mmDevice.getName());
                Log.d("ArduinoBT", "device address is " + mmDevice.getAddress());
                break;
            }
        }
    }
    myLabel.setText("Bluetooth Device Found");
}

void openBT() throws IOException
{
    UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); //Standard SerialPortService ID
    mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);        
    mmSocket.connect();
    mmOutputStream = mmSocket.getOutputStream();
    mmInputStream = mmSocket.getInputStream();

    beginListenForData();

    myLabel.setText("BT  << " + mmDevice.getName()  + " >> is now open ");
}

void closeBT() throws IOException
{
    stopWorker = true;
    mmOutputStream.close();
    mmInputStream.close();
    mmSocket.close();
    myLabel.setText("Bluetooth Closed");
}

void beginListenForData()
{
    final Handler handler = new Handler(); 
    final byte delimiter = 10; //This is the ASCII code for a newline character

    stopWorker = false;
    readBufferPosition = 0;
    readBuffer = new byte[1024];
    workerThread = new Thread(new Runnable()
    {
        public void run()
        {                
           while(!Thread.currentThread().isInterrupted() && !stopWorker)
           {
                try 
                {

                    int bytesAvailable = mmInputStream.available();  
                    if(bytesAvailable > 0)
                    {
                        byte[] packetBytes = new byte[bytesAvailable];
                        mmInputStream.read(packetBytes);
                        for(int i=0;i<bytesAvailable;i++)
                        {
                            byte b = packetBytes[i];
                            if(b == delimiter)
                            {
                                byte[] encodedBytes = new byte[readBufferPosition];
                                System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
                                final String data = new String(encodedBytes, "US-ASCII");
                                readBufferPosition = 0;

                                handler.post(new Runnable()
                                {
                                    public void run()
                                     {
                                        snapText.setText(data);
                                     }
                                });
                            }
                            else
                            {
                                readBuffer[readBufferPosition++] = b;
                            }
                        }
                    }
                } 
                catch (IOException ex) 
                {
                    stopWorker = true;
                }
           }
        }
    });

    workerThread.start();
}


  void offButton() throws IOException
{
    mmOutputStream.write("0".getBytes());
}


void chkcommsButton() throws IOException
{
    mmOutputStream.write("1".getBytes());
}

}

the InputStream.read() method is blocking, that means it will block your code until some data arrive, OR something break the pipe (like a disconnection of the host or closing the stream). Blocking is CPU friendly, as the thread is put on the WAIT state (sleep) until an interrupt put it in the READY state, so it will be scheduled to be run on the CPU; so you WONT use cpu while waiting for data, and this mean you'll use less battery (or that you leave that CPU time to others thread)!

available() gives the actual available data, and because Serial communication is really slow (115200 Baud at 8n1 means 11520 byte/second) and your loop run at least one or two order of magnitude faster, you will read a lot of 0, and using A LOT of cpu to ask for that zero... that means you use a lot of battery.

looping on available is not a problem on the arduino, as you have only one thread/process: your code. BUT in a multi-thread system looping to check for data (that's called "polling") is ALWAYS a bad idea, and should be done only if you have no other choice, and always add a little sleep() so your code won't steal CPU to system and other thread. Good idea is to use blocking call (easy to use for beginner) or an event system like you do for graphics event (not always supported by the library you use, and need synchronization, so it's tricky but you don't spawn other thread in your own code, but remember that data from serial and graphics and your application PROBABLY are in different thread, and should be synchronized)

You are using

import java.util.logging.Handler;

Change it to

import android.os.Handler;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM