Android: Switch between SPP Bluetooth Devices
Asked Answered
U

1

3

I have two different Bluetooth Printers. Bixolon SPP-R200 and Fujitsu FTP-628WSL110. I can connect to each of them separately (using a Samsung Galaxy SII) print, disconnect and reconnect just fine. However, if I switch off the Bixolon and try to pair with the Fujitsu (previously unpaired, Bixolon is still paired), then it fails when trying to connect to the created socket. Same the other way around.

Here is the error message:

07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380): Failed to connect to rfcomm socket.
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380): java.io.IOException: Service discovery failed
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at android.bluetooth.BluetoothSocket$SdpHelper.doSdp(BluetoothSocket.java:406)
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:217)
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at MyApp.BluetoothConnection.connect(BluetoothConnection.java:171)
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at MyApp.AbstractBluetoothPrinter.connect(AbstractBluetoothPrinter.java:34)

Here is the code, which makes the connection attempt, the line that fails under the explained circumstances is btSocket.connect(); - exception see above:

/** Is set in connect() */
private BluetoothSocket btSocket = null;
/** Is set prior to connect() */
private BluetoothSocket btDevice;

public boolean connect(){

        try {
            btSocket = btDevice.createRfcommSocketToServiceRecord("00001101-0000-1000-8000-00805F9B34FB");
            if (btDevice.getName().startsWith("FTP")) {
                //Special treatment for the fujitsu printer
                SystemClock.sleep(1000);
            }
        } catch (Throwable e) {
            LogCat.e(TAG, "Failed to create rfcomm socket.", e);
            return false;
        }

        try {
            // Stop Bluetooth discovery if it's going on
            BluetoothHandler.cancelDiscovery();
            // This fails under the described circumstances
            btSocket.connect();
        } catch (Throwable e) {
            LogCat.e(TAG, "Failed to connect to rfcomm socket.", e);
            return false;
        }

        // Obtain streams etc...
}

I am using the same UUID to connect to both devices (but only one device is switched on at a time, they're never switched on at the same time), the well known SPP UUID from the SDK API:

00001101-0000-1000-8000-00805F9B34FB

Which makes me wonder: Could it be, that I need a different UUID for each device? If yes any idea which?

Unclean answered 2/7, 2012 at 11:8 Comment(0)
U
10

Ok after several days of trying different solutions, I am now able to switch between the afore mentioned printers. Since I am not entirely sure which of my measures was the reason for succeeding, I'll list them all, so someone stumbling upon this post will have some clues on how to fix his bluetooth issues. One thing however I am quite sure about: You don't need different UUIDs to connect two different printers - you can use the same UUID (But I only ever have one of them switched on).

I cache the device that was last printed to - however unlike before I no longer cache the actual BluetoothDevice, instead I only cache it's mac address which is obtainable through:

BluetoothDevice bluetoothDevice; 

//Obtain BluetoothDevice by looking through paired devices or starting discovery

bluetoothDevice.getAddress(); 

getAddress() returns a String: The hardware address of the device. I cache that mac address and next time the user wants to print, I match the cached mac address against the mac addresses of all paired printers - if the mac address matches one of these, I try to connect to that printer. If that fails, I reset my cached mac address and try to find another device by first checking my paired devices if one of them can connect (if I can successfully connect I update my cached mac address accordingly), and if that fails I start a bluetooth discovery looking for other potential devices.

Now in order to not leave any socket connections open to one of my printers my routine is as follows (I'll leave out the try-catches I have wrapped around each call to ease the read):

Create the socket

BluetoothSocket btSocket = btDevice.createRfcommSocketToServiceRecord(MY_UUID);

The MY_UUID refers to the well known UUID used for connecting to SPP devices:

00001101-0000-1000-8000-00805F9B34FB

If the socket creation fails (which is rare and if it happens it's most likely due to insufficient permissions or bluetooth being disabled/not available), we can't proceed further, as we need a socket to connect to. Hence, in your catch block you should trigger the disconnect method (more on that later).

Connect to the created socket

bSocket.connect();

If the connect fails, we can't proceed further, as we need a valid socket connection to obtain the input and output streams. Hence, in your catch block you should trigger the disconnect method (more on that later).

Obtain the input and output stream

The next step would be to obtain the input and output streams from the socket. I do this in a for loop which runs a couple of times (5 times should be enough) - in each iteration I check if I have the output stream, if not, I try to obtain it, same for the input stream. At the end of the loop I check if I have both my streams, if yes I exit the loop (AND the whole connect method), if no, I proceed with the loop and try again. Usually I get both my streams in the first loop-iteration, however sometimes I need two or three iterations to obtain both streams.

If I reach the code that follows after the loop declaration I obviously did not get my streams or something else went wrong. At this point the connect is considered to have failed and I execute my disconnect code (which cleans up open streams & sockets, more on that later).

Read/Write

Now that you have a connection to your target bluetooth device you can perform read and write operations. Once you're done you should cleanup by closing all streams and sockets, more on this in the next paragraph: Disconnecting. Remember: If an exception occurs during read/write operations, be sure to trigger the disconnect method in order to cleanup your resources. If your printer needs some kind of initialization command, be sure to send that right after connecting to the printer and before performing your read/write operations.

Disconnecting

There are usually two occasions on which you should disconnect:

  • Once you're done with your read/write operations
  • If an exception occurred somewhere along the way, to cleanup your resources

Close your streams

The first thing you want to do is cleanup your streams, check both, your input and output stream, if they're not null, close them and set them to null. Be sure to wrap each operation (closing the input stream, closing the output stream etc...) into its own try-catch as otherwise failing to do one cleanup (Because an exception is raised) will skip all other cleanup measures.

Close the socket

Now that you've made sure your input streams are cleaned up, proceed to closing your socket connection and setting it to null thereafter.

One more thing: I have a Thread.sleep at the beginning and end of my disconnect method. The one in the beginning is about 2.5 seconds (= 2500 milliseconds) long, the purpose is to make sure nothing else is going on with the printer (such as pending read/write operations or the printer still printing etc..). The second Thread.sleep is at the end of my disconnect method and is about 800 milliseconds long. The reason for that sleep at the end is related to the problems I had when trying to immediately open a new socket right after closing one. For more details please refer to this answer.

Questions?

In case anyone has questions related to my OP or my answer, please let me know in the comments and I'll try my best to answer them.

Unclean answered 6/7, 2012 at 8:20 Comment(4)
Could you please check this question please? :DKwapong
@Skizo I did, and it sounds like the answer here is exactly what you need? If that is not working for you, please let me know what the problem is.Unclean
I'm using this code it's more or less the example of the Android documents repo but it still saying that it's not connectedKwapong
@Skizo: The link is not working xD. Did you try reading the answer provided here and adjust your code accordingly? Also - did you check the logfiles? Make sure to look out for exceptions/reasons as to why it is not working.Unclean

© 2022 - 2024 — McMap. All rights reserved.