Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a Bluetooth SPP connection process more reliable?

We are about to release the new version of our software, and for the version afterward, our goal is to make the connection process for our Bluetooth SPP connections more reliable. We use the RN42 module in our products, and currently, at times it may take more than one try to connect to our boards.

Here is my current code:

class ConnectThread extends Thread {
    BluetoothDevice mDevice;

    public ConnectThread(BluetoothDevice device) throws SecurityException, NoSuchMethodException {
        mDevice = device;
        UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
        try {
            btSocket = mDevice.createInsecureRfcommSocketToServiceRecord(uuid);
        } catch (IOException e) {
            Log.e("Error", "Could not create socket!");
        }
    }

    public void cancel() {
        interrupt();
        try {
            Log.i("Treadmill", "in connect thread cancellation");
            btSocket.close();
        } catch (IOException localIOException) {
            Log.e("Treadmill", "exception + " + localIOException.getMessage());
        }
    }

    public void run() {
        btAdapter.cancelDiscovery();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Log.e("whatever", "InterruptedException: " + e.getMessage(), e);
        }
        try {
            btSocket.connect();
            Log.i("Treadmill", "After Connect");
        } catch (IOException ioe) {
            Log.i("Treadmill", "Trying Fallback");
            try {
                Method m;
                try {
                    btSocket.close();
                    m = mDevice.getClass().getMethod("createInsecureRfcommSocket", new Class[]{int.class});
                    btSocket = (BluetoothSocket) m.invoke(mDevice, 1);
                    Thread.sleep(500);
                    btSocket.connect();
                } catch (IllegalArgumentException e) {
                    Log.e("whatever", "IllegalArgumentException: " + e.getMessage(), e);
                } catch (IllegalAccessException e) {
                    Log.e("whatever", "IllegalAccessException: " + e.getMessage(), e);
                } catch (InvocationTargetException e) {
                    Log.e("whatever", "InvocationTargetException: " + e.getMessage(), e);
                } catch (NoSuchMethodException e) {
                    Log.e("whatever", "NoSuchMethodException: " + e.getMessage(), e);
                } catch (InterruptedException e) {
                    Log.e("whatever", "InterruptedException: " + e.getMessage(), e);
                }

            } catch (IOException ioe2) {
                Log.e("Treadmill", "Failed to connect to Bluetooth device: " + ioe2.getMessage());
                eventHandler.obtainMessage(MESSAGE_ERRORCONNECT, 0, 0, getResources().getString(R.string.connerr) + ": " + ioe2.getMessage()).sendToTarget();
                try {
                    btSocket.close();
                } catch (IOException localIOException2) {
                    Log.e("Error", "IO Exception!");
                }
                return;
            }
        }
        eventHandler.obtainMessage(MESSAGE_CONNECT, 0, 0, "").sendToTarget();
        synchronized (this) {
            connectThread = null;
        }
        manageConnectedSocket(btSocket);
    }
}

Even with the fallback to reflection the connection intermittently fails on some devices. I get the following error:

find_rfc_slot_by_id unable to find RFCOMM slot id: XX (XX being a number that increments on each attempted connection).

followed by this: Failed to connect to Bluetooth device: read failed, socket might closed or timeout, read ret: -1

Does anyone know how to avoid these errors.

Interestingly, for comparison. I am testing on two tablets. One tablet, the Samsung Galaxy Tab 4 seems to work extremely well, while another, the Astro Tab A10, seems to be a bit more intermittent unless you wait several seconds between connecting and disconnecting.

like image 608
Pink Jazz Avatar asked Apr 26 '18 15:04

Pink Jazz


People also ask

What is Bluetooth SPP mode?

Serial Port Profile (SPP) It's is one of the more fundamental Bluetooth profiles (Bluetooth's original purpose was to replace RS-232 cables after all). Using SPP, each connected device can send and receive data just as if there were RX and TX lines connected between them.

Does Android support Bluetooth SPP?

Android allows communication with Bluetooth devices which have SPP.

What is Bluetooth RFCOMM?

Radio frequency communication (RFCOMM) The Bluetooth protocol RFCOMM is a simple set of transport protocols, made on top of the L2CAP protocol, providing emulated RS-232 serial ports (up to sixty simultaneous connections to a Bluetooth device at a time). The protocol is based on the ETSI standard TS 07.10.


1 Answers

For more reliable connection means even app was closed, Bluetooth should be keep connected in the background. Below is the working solution I followed in my app to keep Bluetooth connection background. First create a class which extends service, because service runs in the background even app closed until you call stopService or stopSelf methods

while starting BluetoothService class pass Bluetooth Mac address to connect and run in the background. Sample code:

   @Override
public int onStartCommand(Intent intent, int flags, int startId) {

    if (intent != null){
        String deviceg = intent.getStringExtra("bluetooth_device");

        if (deviceg != null){
            connectToDevice(deviceg);
        }

    }

    return START_STICKY;
}

Below is the connect to device method which identifies mac Address into Bluetooth Device.

   public synchronized void connectToDevice(String macAddress){
    BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(macAddress);

    if (mConnectedThread != null){
        mConnectedThread.cancel();
        mConnectedThread = null;
    }
    mConnectThread = new ConnectBtThread(device);
    toast("connecting");
    mConnectThread.start();

}

This is my Thread class inside BluetoothService which runs in a separate thread Code:

 private class ConnectBtThread extends Thread{
    private final BluetoothSocket mSocket;
    private final BluetoothDevice mDevice;

    public ConnectBtThread(BluetoothDevice device){
        mDevice = device;
        BluetoothSocket socket = null;
        try {
            socket = device.createInsecureRfcommSocketToServiceRecord(UUID.fromString(B_UUID));
        } catch (IOException e) {
            e.printStackTrace();
        }
        mSocket = socket;

    }

    @Override
    public void run() {
        if (mBluetoothAdapter.isDiscovering()){
            mBluetoothAdapter.cancelDiscovery();
        }

        try {
            mSocket.connect();
            Log.d("service","Bluetooth one running (connected)");

        } catch (IOException e) {

            try {
                mSocket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }
        connected(mSocket);

    }

    public void cancel(){

        try {
            mSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

It works perfectly fine for our app. If you want to access service methods bind this service to your activity

like image 90
Bhanu Prakash Pasupula Avatar answered Oct 06 '22 01:10

Bhanu Prakash Pasupula