Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I properly connect an Android application to an RFCOMM socket on a Bluetooth enabled Arduino microcontroller?

I'm working with some students at my university developing a simple Bluetooth Android application that will be used for serial communication (RFCOMM) to an Arduino microcontroller with a Bluetooth module connected to it.

To the best of my knowledge, I'm using the correct Bluetooth address and UUID for RFCOMM/SPP 00001101-0000-1000-8000-00805F9B34FB. My application starts a thread that attempts to connect to the device using BluetoothDevice.createRfcommSocketToServiceRecord(UUID). But for one reason or another, we are not seeing a successful connection. The operation always fails upon invoking connect() on the resulting BluetoothSocket that comes from the invocation above.

When tested on my HTC Evo, running HTC's variant of Gingerbread, the connect() call usually fails with the exception message "Service Discovery Could Not Be Started." I did some reading and found that some said that HTC's implementation for RFCOMM in the Bluetooth stack was buggy, so we decided to try it on another student's Samsung Galaxy S. The first time the code ran, everything worked perfectly. The Arduino microcontroller is connected to a small electric motor which began working as expected. I have not ruled out whether or not the problem could be on the microcontroller's side.

Subsequent uses of the application on the Samsung device then failed, now with a message saying "Service Discovery Failed". To me, it seems that perhaps the Bluetooth module on the device side thinks that the RFCOMM service is still in use. But we've restarted the microcontroller and still saw the same result.

I've just listed the thread code as it is all that is really relevant. I've read that there is a pretty common workaround (hack) for these issues using reflection. My attempts at it have also failed but are there and commented out. Hopefully someone can steer me in the right direction here. Also note that I do have the necessary permissions enabled in the manifest and in both cases, the device was successfully paired to the Arduino using Android's user interface.

private class ClientThread extends Thread {

    private String _btAddress;

    /**
     * A handle to the local device's Bluetooth adapter hardware.
     */
    private BluetoothAdapter _btAdapter = BluetoothAdapter.getDefaultAdapter();

    /**
     * A handle to the remote device Bluetooth context.
     */
    private BluetoothDevice _btRemoteDevice;

    /**
     * A handle to the Bluetooth serial socket.
     */
    private BluetoothSocket _btSocket;

    /**
     * Constructor.
     * @param btAddress The BluetoothHardware address.
     */
    public ClientThread(String btAddress)
    {
        _btAddress = btAddress;
    }

    public void run()
    {
        // Retrieves the device identified by the _btAddress property.
        _btRemoteDevice = retrieveDevice();
        if ( _btRemoteDevice == null )
            sendUIMessage( CONNECTION_BT_DEVICE_NOT_BONDED );
        else
            sendBeacon();
    }

    /**
     * Retrieves the device associated with this client thread.
     * @return
     */
    private BluetoothDevice retrieveDevice()
    {
        Set<BluetoothDevice> btDevices = _btAdapter.getBondedDevices();
        for (BluetoothDevice btd : btDevices)
        {
            String addr = btd.getAddress();
            String name = btd.getName();
            if ( addr.equalsIgnoreCase(_btAddress) )
                return btd;
        }
        return null;
    }

    /**
     * Sends the beacon to the Bluetooth device.
     */
    private void sendBeacon()
    {
        // Holds the output stream of the BluetoothDevice.
        OutputStream os = null;

        try
        {
            _btSocket = _btRemoteDevice.createRfcommSocketToServiceRecord( UUID.fromString( "00001101-0000-1000-8000-00805F9B34FB" ) );

            //Method m = _btRemoteDevice.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
            //_btSocket = (BluetoothSocket) m.invoke(_btRemoteDevice, 1);
            _btSocket.connect();
            os = _btSocket.getOutputStream();
            os.write('L');
        }
        catch (IOException e)
        {
            String message = e.getMessage();
            e.printStackTrace();
            sendUIMessage(CONNECTION_FAILURE_IO);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            sendUIMessage(CONNECTION_FAILURE_UNKNOWN);
        }
        finally
        {
            try
            {
                if (_btSocket != null)
                    _btSocket.close();
            }
            catch (IOException e)
            {
                System.out.println("Failed closing Bluetooth output stream.");
                e.printStackTrace();
            }
        }
    }
}

EDIT: The Bluetooth module is an MDFLY RF-BT0417CB. I know that the code that is running on the arduino is not much and is simply communicating with the BT module using Serial.available() and Serial.read(). However I have a new piece of information that may be of more use. When my application was installed on the Samsung device, it worked just once, and failed on subsequent trials. A while back, the other student I'm working with, used Android App Inventor (a drag and drop GUI tool that also can create logical working artifacts) to create a simple application that connects the same BT module/arduino board, which worked. He said that when my application was installed, that the other application was unable to ever connect to the BT module, which leads me to believe the system stayed thinking that the resource was allocated to my application. After he uninstalled my app, the other was able to connect. He does not have the source code to the other application, but I am going to try App Inventor myself to see if the source code it generates it generates is doing anything different. To the best of my knowledge, I am complying with most of the standard practices defined in Android's documentation, so perhaps it's something strange about the BT module or the fact that the arduino code isn't necessarily programmatically controlling the BT module.

ANOTHER EDIT: I'm not a Bluetooth expert, but we were able to figure out a work around. As some are aware, there are a bunch of public BluetoothDevice API's, hidden at compile time, but are legally public at runtime using reflection. One of them is createRfCommSocket(int). This API is not in the official documentation since it is hidden, but you can read it here. I haven't tried it yet with the documentation supported API, but the problem appeared to be something of a concurrency issue between the handset and the serial board. The handset sent a message, which is of course a blocking call, and when it returned from there, closed the connection. The shield on the serial board would then also close the connection and hence the data was not available to the arduino application. We realized this when witnessing successful communication while in debug mode on the android side, but failure in release mode. Adding a half second delay on the android side, between the transmission and closure of the BluetoothSocket fixed the issue. I cannot say whether this issue was attributed to by the arduino code or not as I am not very familiar with the architecture, but we as students lack experience so it wouldn't surprise me.

like image 349
Joey Carson Avatar asked Nov 02 '11 19:11

Joey Carson


1 Answers

Communication Between Android And Arduino With Bluetooth(1)

I think this will be helpful to you. Can you provide some detail on this.I have seen one link ,you can see this too. Let me know whether this is helpfull or no? How to create Insecure RFCOMM Socket in Android?

like image 145
mH16 Avatar answered Nov 14 '22 03:11

mH16