Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bluetooth connection issues with IntentService

I need to transmit some data from my Android app over Bluetooth (to Arduino). I am not reading/receiving anything back from Arduino. For my single threaded needs, I went with an IntentService. After pairing, my code works fine for the first time I connect and send data. I disconnect after sending data without errors. But when I try to connect the second time onwards, I get the following error when I try myBluetoothSocket.connect() :

read failed, socket might closed or timeout, read ret: -1

Only solution is to power off the Arduino device and reconnect (it doesn't help if I force stop the app and try reconnecting).

Note that everything works fine if I spawn 2 threads (one for read and write each) regardless of how many times I connect and send data (thereby proving there is nothing wrong on the Arduino side, "holding back" an old connection).

Here is my Android code :

import android.app.IntentService;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.Context;
import android.os.Build;
import android.os.ParcelUuid;
import android.widget.Toast;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.UUID;

public class DataTransmissionService extends IntentService {

    private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    private static final String TAG = "DataTransmissionService";

    private BluetoothAdapter btAdapter = null;
    private BluetoothSocket btSocket = null;
    private OutputStream outStream = null;
    private BluetoothDevice device = null;

    public DataTransmissionService() {
        super("DataTransmissionService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        cleanup();
        if (intent != null){

            btAdapter = BluetoothAdapter.getDefaultAdapter();
            pairedDeviceAddress = "already_paired_device_mac_addr";

            try {
                log.d(TAG, pairedDeviceAddress);
                device = btAdapter.getRemoteDevice(pairedDeviceAddress);
                log.d(TAG, "Device bond state : " + device.getBondState());

            } catch (Exception e) {
                log.e(TAG, "Invalid address: " + e.getMessage());
                return;
            }

            try {
                btSocket = createBluetoothSocket(device);
            } catch (IOException e) {
                log.e(TAG, "Socket creation failed: " + e.getMessage());
                return;
            }

            try {

                if (!btSocket.isConnected()) {  
                    btSocket.connect();    
                    log.d(TAG, "Connected");
                } else {
                    log.d(TAG, "Already Connected");  //flow never reaches here for any use case
                }

            } catch (IOException e) {
                log.e(TAG, "btSocket.connect() failed : " + e.getMessage());
                return;
            }

            try {
                outStream = btSocket.getOutputStream();
            } catch (IOException e) {
                log.e(TAG, "Failed to get output stream:" + e.getMessage());
                return;
            }

            sendData("test");
           //cleanup();   called in onDestroy()

        }

    }

    @Override
    public void onDestroy(){
        cleanup();
        //notify ui
        super.onDestroy();
    }

    private void cleanup(){

        try {
            if (outStream != null) {
                outStream.close();
                outStream = null;
            }
        } catch (Exception e) {
            log.e(TAG, "Failed to close output stream : " + e.getMessage());
        }

        try {
            if (btSocket != null) {
                btSocket.close();
                btSocket = null;
            }
        }catch (Exception e) {
            log.e(TAG, "Failed to close connection : " + e.getMessage());
        }

    }

    private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
        /*if(Build.VERSION.SDK_INT >= 10){
            try {
                final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
                return (BluetoothSocket) m.invoke(device, MY_UUID);
            } catch (Exception e) {
                log.e(TAG, "Could not create Insecure RFComm Connection",e);
            }
        }*/

        return  device.createRfcommSocketToServiceRecord(MY_UUID);
    }

    private void sendData(String message) {

        byte[] msgBuffer = message.getBytes();
        log.d(TAG, "Sending : " + message);
        try {
            outStream.write(msgBuffer);
        } catch (IOException e) {
            log.e(TAG, "failed to write " + message);
        }
    }
}

I have tested on Nexus 5 and Samsung S5 devices (running 5.1 and 5.0 respectively).

like image 583
dev Avatar asked May 16 '15 01:05

dev


1 Answers

When you try to connect the second time you have to create the corresponding socket again.

Also you must consider Arduino is a slow platform, there might be some considerable delay between closing the connection and you being able to open it again.

like image 136
Pat Avatar answered Oct 11 '22 06:10

Pat