Connecting to a Bluetooth Scanner with Xamarin Android

Hi All,

I am working on a project where I need to connect to a bluetooth scanner(Motorola CS3070). I need to capture the input stream and use it to populate a list box with the scanned barcode. I tried to create a secure socket and connect to it, but the socket fails to connect. (The device is ON and paired. Its working as a physical keyboard and populates the scanned code if cursor is in a editable field). This is my code:

public void InitializeBluetooth()
    {
        // Get local Bluetooth adapter
        bluetoothAdapter = BluetoothAdapter.DefaultAdapter;

        // If the adapter is null, then Bluetooth is not supported
        if (bluetoothAdapter == null)
        {
            Toast.MakeText(this, "Bluetooth is not available", ToastLength.Long).Show();
            Finish();
            return;
        }

        // If bluetooth is not enabled, ask to enable it
        if (!bluetoothAdapter.IsEnabled)
        {
            var enableBtIntent = new Intent(BluetoothAdapter.ActionRequestEnable);
            StartActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }

        // Get connected devices
        var listOfDevices = bluetoothAdapter.BondedDevices;
        if (listOfDevices.Count > 0)
        {
            foreach (var bluetoothDevice in listOfDevices)
            {
                UUID = bluetoothDevice.GetUuids().ElementAt(0);
                if (!deviceDictionary.ContainsKey(bluetoothDevice.Name))
                    deviceDictionary.Add(bluetoothDevice.Name, bluetoothDevice.Address);
            }
        }
        else
        {
            connectButton.Text = "Scanner Not connected";
            connectButton.Clickable = false;
        }

        if (bluetoothAdapter.IsEnabled && listOfDevices.Count > 0)
        {
            if (listOfDevices.ElementAt(0).BondState == Bond.Bonded)
            {
                pairedBTDevice = listOfDevices.ElementAt(0);
                mySocket = pairedBTDevice.CreateRfcommSocketToServiceRecord(UUID.Uuid);
                var thread = new Thread(BTConnect);
                thread.Start();
            }
        }
    }

    public static void BTConnect()
    {
        try
        {
            mySocket.Connect();
            _activity.RunOnUiThread(() => connectButton.Text = " Scanner Connected");
            _activity.RunOnUiThread(() => connectButton.Clickable = false);
            receiver.loop = true;
            var thread = new Thread(BTRead, "BTRead");
            thread.Start();
        }
        catch (Exception e)
        {
            _activity.RunOnUiThread(() => Toast.MakeText(_activity.ApplicationContext, "Couldn't connect. Is the device on and paired?", ToastLength.Long).Show());
            _activity.RunOnUiThread(() => connectButton.Text = "Scanner Not connected");
            _activity.RunOnUiThread(() => connectButton.Clickable = true);
            receiver.loop = false;
        }
    }

The code gives an exception at the line mySocket.Connect(); The exception is Java.IO.IOException: "read failed, socket might closed or timeout, read ret: -1"
I also tried to create a fallback socket with some example I found on StackOverflow here but that didn't help me. Can someone please help me resolve this.

Thanks

Posts

  • @GrahamMcKechnie‌ Thanks a lot for the detailed answer Graham.

    You are assuming the Uuid is what you want with ElementAt(0)

    You were absolutely correct there, I was assuming that the default UUID was for the serial port profile and it turned out it was an incorrect one. I reconfigured my device and used your code for the ConnectAsync(); and it resolved my problem.

    Thanks you very much :smile:

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    @GrahamMcKechnie I have take a look to your code.
    I try to "merge" your code in BluetoothChat example but I have some problems:
    1) BluetoothService.SerialPort: I can't find this constant
    2) ParcelUuid[] uuids = device.GetUuids(); GetUuids does not exists...

    Can you help me ?
    Thanks

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    @SourabhSinghRathore have you an example prj I can take a look? I have your same problem

  • GrahamMcKechnieGrahamMcKechnie AUMember ✭✭✭

    Alessandro

    1. I've already provided the value of Bluetooth.SerialPort in the post above.
    2. GetUuids() is in the class BluetoothDevice.
  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    Graham, I don't know.
    I am not able to find GetUuids()

    https://www.dropbox.com/s/3aakvn2tt8vo0bt/Screenshot 2015-12-31 00.34.50.png?dl=0

  • GrahamMcKechnieGrahamMcKechnie AUMember ✭✭✭

    Obviously a compiler error. Somehow you aren't picking up the correct assembly. What is your android:minSdkVersion and android:targetSdkVersion in your AndroidManifest.xml. I was using 17 and 21 respectively in my example at that time. Also do you have the correct Bluetooth permissions in your AndroidManifest.

    What type of device are you trying to connect to?

    Once you get your assemblies sorted I would advise not trying to merge it into Bluetoothchat example. Go with the approach I outlined which is a .Net approach which doesn't try to emulate the original java code of the chat example.

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    This is

    https://www.dropbox.com/s/fjt265qhvxa0lo8/Screenshot 2015-12-31 19.23.15.png?dl=0

    I'm trying to connect to a Mediacom Tablet.

    Have you a full working example that you can post?

  • GrahamMcKechnieGrahamMcKechnie AUMember ✭✭✭

    I meant what type of SPP device are you trying to connect to, not your Android device. I'm sorry, but the code is part of an app and I'm not going to post the app. I've already posted everything that is relevant for connecting to a SPP device. Your error is just a typical .NET error related to the fact that you aren't referencing the correct assembly.

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    @GrahamMcKechnie , assembly is correct.
    The device is connected to a barcode reader Datalogic Quick Scan.
    I am able to connect to the Scanner. I would like only to have some suggestions about a "continuos reading" of the socket.
    I have implemented this code, but I don't know if it's well done (the While(true)....)

                    Task.Run (async() => {
                        await BthSocket.ConnectAsync ();
    
                        if(BthSocket.IsConnected){
                            System.Diagnostics.Debug.WriteLine("Connected!");
                            var mReader = new InputStreamReader(BthSocket.InputStream);
                            var buffer = new BufferedReader(mReader);
                            while (true){
    
                                string barcode = await buffer.ReadLineAsync();
                                if(barcode.Length > 0)
                                    System.Diagnostics.Debug.WriteLine("Read: " + barcode);
    
                            }
    
                        }
    
                    });
    

    How do you have a continuous reading in your code?

    Thanks for your help

  • GrahamMcKechnieGrahamMcKechnie AUMember ✭✭✭
    edited January 2016

    Alessandro,

    I've never written code for a barcode reader, so I probably shouldn't be advising you. Having a guess at it though, I'd attempt it like the following

    However first a couple of comments. I would make the ConnectAsync method a separate method of a BarcodeReceiver class. I would guess you connect and disconnect once only while the app operates. Connecting/disconnecting should be totally separate to actual reading of the barcode. Therefore establish a connection and then start a new thread in the BarcodeReceiver class that just permanently reads in a loop while you have a Bluetooth connection.

    The following code presumes the barcode always has some terminating character, so that you know you have read the complete barcode.

    inputStream = bluetoothSocket.InputStream;
    int bufferSize = 1024;
    byte[] buffer = new byte[bufferSize];
    ASCIIEncoding encoder = new ASCIIEncoding();
    while (bluetoothSocket.IsConnected)
    {
        string response = string.Empty;
        int bytesRead = inputStream.Read(buffer, 0, buffer.Length);
    
        if (bytesRead != 0)
        {
            response = encoder.GetString(buffer, 0, bytesRead);
                barcodeMessage.Append(response);
    
            if ((!string.IsNullOrEmpty(response)) && (response.Contains(terminatingChar)))
                {
                string completedBarcode = barcodeMessage.ToString();
                currentContext.Post((e) =>
                        {
                            if (BarcodeMessageReceived != null)
                                    BarcodeMessageReceived (this, new BarcodeMessageReceivedEventArgs(completedBarcode));
                        }, null);
            }
    }
    }
    

    This would post back to a BarcodeInterpreter class which would do whatever you have to do with a barcode. The BarcodeInterpreter would then raise events on the MainActivity or Fragment, that I presume would fill a listview for each barcode item read.

    Once you get it all working, I'd then run it as a BarcodeService.

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    Thanks @GrahamMcKechnie , this is very useful

  • shubhrakushalshubhrakushal USMember ✭✭

    could I get the complete source code for the above problem?

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    I have this little repo

    https://github.com/acaliaro/TestBth

  • parth7676parth7676 USMember ✭✭

    Thanks @AlessandroCaliaro for the little, but helpful repo.
    And for those who don't want to afford for a real barcode scanner they can use this app Wireless Barcode-Scanner

  • PieterjanDeClippelPieterjanDeClippel USMember ✭✭
    edited February 2017

    I've been struggling with this problem also. But I've finally found the issue.
    When I populated a ListView with BondedDevices and used the ListView.ItemClick event,
    the ListView_ItemClick eventhandler was fired multiple times in a row (like 5 times).
    Which meant that the Xamarin-app was trying to connect to the device 5 times in a row.
    This causes the error Java.IO.IOException: "read failed, socket might closed or timeout, read ret: -1"

    Wrong way:

    public class MainActivity : Activity
    {
        protected override void OnStart()
        {
            base.OnStart();
            ListView list = FindViewById<ListView>(Resource.Id.listBonded);
            list.ItemClick += Bonded_ItemClick;
        }
    }
    

    Right way:

    public class MainActivity : Activity
    {
        protected override void OnStart()
        {
            base.OnStart();
        }
    
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            SetContentView(Resource.Layout.Main);
    
            ListView list = FindViewById<ListView>(Resource.Id.listBonded);
            list.ItemClick += Bonded_ItemClick;
        }
    }
    

    Don't know if this helps,
    But it's important anyway to only bind the ItemClick event on OnCreate.

    I've uploaded a working example to my webserver:
    https://tutorials.pieterjan.pro/download/XamarinBluetooth.zip

Sign In or Register to comment.