Unable to read from a Bluetooth socket

I am trying to communicate with a Bluetooth device.
I have succeeded in outStream.Write(outBuf, 0, outBuf.Length); but int readLen = inStream.Read(inBuf, 0, inBuf.Length); never returns.

I am sure that the device has successfully received the bytes I sent and returned some bytes.
I have written a Java version of this program and it works well, but now get problem on C# Xamarin.

Here is my code, please anybody help me:

        BluetoothSocket btSocket = null;
        BluetoothAdapter mBluetoothAdapter = null;
        try{
            mBluetoothAdapter = BluetoothAdapter.DefaultAdapter;
        }
        catch (Exception e){

        }
        if (mBluetoothAdapter == null){
            return null;
        }


        ICollection<BluetoothDevice> boundSet = mBluetoothAdapter.BondedDevices;
        BluetoothDevice btDevice1 = boundSet.ElementAt(0);
        btSocket = btDevice1.CreateRfcommSocketToServiceRecord(UUID.FromString("00001101-0000-1000-8000-00805F9B34FB"));
        mBluetoothAdapter.CancelDiscovery();
        try{
            btSocket.Connect();
        }
        catch (Exception e)
        {
            return e.Message;
        }

        Stream outStream = btSocket.OutputStream;
        Stream inStream = btSocket.InputStream;
        //inStream.ReadTimeout = 5000;
        byte[] outBuf = new byte[5] { 0xAC, 0x00, 0x00, 0x74, 0xAA };
        byte[] inBuf = new byte[1];
        outStream.Write(outBuf, 0, outBuf.Length);

        int readLen = inStream.Read(inBuf, 0, inBuf.Length);   //This line NEVER returns.
        return string.Format("readLen{0} {1} readRet!", readLen, inBuf[0]);

Thank you very much.

Posts

  • CheesebaronCheesebaron DKInsider, University mod

    Almost all the samples I see run the Read method of the InputStream in a while loop, you might have been lucky that you got a response at that exact time in your Java code to receive something.

    So what I would do is to create a thread where you listen for input, then after that has been established start sending stuff to the bluetooth device.

  • TomYangTomYang USMember

    Thank you Tomasz. You inspired me to partially work this out.
    I added a line of Thread.sleep(5000); before inStream.Read and successfully got the returned bytes of the device.

    But this is terrible for 2 things:
    1 Call to inStream.Read never returns unless there is already returned bytes. It will not return even the device returned bytes several milliseconds later.
    2 This Xarmarin Bluetooth socket does not suppot setting read-timeout for inputstream.

    If these guesses are true, Xamarin is totally useless on Bluetooth communication.

  • DWestyDWesty USMember ✭✭

    @TomYang there are any number of issues you could be seeing keep in mind Bluetooth on android is finicky to say the least.

    You can't set timeouts to read in native android either you have to write code in C if you want that with Android.

    Read a byte at a time in a while loop on a different thread....

  • TomYangTomYang USMember

    @DWesty Thank you for your information.

    I've moved the inStream.Read into a separate thread and read with a byte[1] array.

    But it seems that it will still stuck if I try to read the 8th byte while there are only 7bytes returned. According to MSDN it seems that stream.Read is designed to be this. So I have to know how many bytes to read myself. Am I correct?

    But this is terrible because bytes may be lost during wireless communication. For example according to communication protocol I have to read 7 bytes while there are 4 bytes lost during communication. The program will get stuck forever.

    Here is my code of AsyncDelegate on implementing extra thread for inStream.Read():

        static int TakesAWhile()
        {
            byte[] buf = new byte[1];
            int tmpLen = 0;
            int readLen = 0;
            while (readLen < 8 && (tmpLen = inStream.Read(buf, 0, 1)) > 0)//I have to know when to stop, in this case I read no more than 8bytes.
            {
                inBuf[readLen] = buf[0];
                readLen += 1;
            }
            return readLen;
        }
    
        public delegate int TakesAWhileDelegate();
    
  • TomYangTomYang USMember

    This problem can be solved circuitously:

    Put inStream.Read() in a timer which will be Disposed after a period.

    Timer.Dispose() will cause inStream.Read() to throw an IoException and exit.

    From this way I broke the stuck forcibly.

  • TomYangTomYang USMember
    edited December 2013

    This problem has finally been solved by my senior software colleague, which had troubled the Xamarin official custom service too.

    put the following lines in a while loop before bluetoothDevice.read(byte[]):

    if (!inStream.CanRead || !inStream.IsDataAvailable()) continue;

    There will be no potential stuck any more.

  • FLeeFLee USMember

    Guys, I have problem to connect the bluetooth socket in Xamarin. Similar code works fine in pure android java code.
    this._bluetoothSocket.Connect();

    The above line always throw IOException and I tried to use the different bluetooth UUID when creating the socket.

    java.io.IOException: read failed, socket might closed or timeout, read ret: -1
    at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:1016)
    at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:1036)
    at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:654)

    The bluetooth device is already connected.

    Any suggestion?

    Thanks
    FLee

  • CheesebaronCheesebaron DKInsider, University mod

    @FLee not really relevant to this thread. Create a new one.

  • SKallSKall USMember ✭✭✭✭

    @TomYang, you might want to also change the Read into ReadAsync call (with a cancellation token). This makes it much easier to handle incoming messages.

  • ReubenCoutinhoReubenCoutinho AUMember
    edited May 2015

    Hey guys, I am not able to read from a Bluetooth socket too. I am trying to implement the solution by @TomYang , but I can't seem to make it work. I have tried this method to do it, but I can't seem to get the length, as it says "System.NotSupportedException: Operation is not supported."

    while (androidBluetoothConnectionComponents.connectionAlive () && !inStream.CanRead && !inStream.IsDataAvailable()) {
                        // do nothing until a byte is available from input stream
                        Log.Debug (TAG, "Doing nothing while waiting for next byte | CanRead = " + inStream.CanRead);
                    }
                    byte[] result;
                    int length;
                    if (androidBluetoothConnectionComponents.connectionAlive ()) {
                        length = (int)inStream.Length;
                        result = new byte[length];
                        await inStream.ReadAsync (result, 0, length);
                        return result;
                    }
    

    I am a complete noob in this, so any help would be appreciated.

  • DimitarIvanovDimitarIvanov USMember ✭✭

    @TomYang I have a blog spot about bluetooth classic reading/writing you can see it here if you find it helpfull -> http://firmwareninja.blogspot.com/2014/06/xamarinandroid-connecting-with.html

  • ReubenCoutinhoReubenCoutinho AUMember

    @DimitarIvanov I don't understand the language :expressionless:

  • DimitarIvanovDimitarIvanov USMember ✭✭
    edited May 2015

    @ReubenCoutinho Try with the comments and the xamarin.Android documentation to make it work for you,this example was made in course here in my country and as a such is in native language.
    But I am very sure that using the comments and the Xamarin.Android you can reuse it

  • ReubenCoutinhoReubenCoutinho AUMember
    edited May 2015

    Thanks @DimitarIvanov ! I'll try and work it out from there... :smile: I'm just a bit desperate to get my project done..

  • JeffGonzalesJeffGonzales USMember ✭✭

    @TomYang I see InputStream.CanRead but I don't see InputStream.IsDataAvailable().

  • ireshikaireshika USMember ✭✭

    i also faced with this problem,you could solve it in 2 ways , as mentioned earlier use reflection to create the socket
    Java.Lang.Reflect.Method mi = device.Class.GetMethod("createRfcommSocket",new Java.Lang.Class[] { Java.Lang.Integer.Type } );

    BthSocket= (Android.Bluetooth.BluetoothSocket)mi.Invoke(device, 1);

    Second one is, client is looking for a server with given UUID and if your server isn't running parallel to client then this happens. Create a server with given client UUID and then listen and accept the client from server side.It will work.

  • jaspal6015jaspal6015 Member ✭✭

    [email protected]

    Hope you are fine and i need your help to resolve my below issue
    my connection is not going to connect with device and showing me error
    "read failed, socket might closed or timeout, read ret: -1"

    My code is listed below:-

    try
    {
    adapter = BluetoothAdapter.DefaultAdapter;
    if (adapter == null)
    throw new Exception("No Bluetooth adapter found.");

                if (!adapter.IsEnabled)
                    throw new Exception("Bluetooth adapter is not enabled.");
    
                ICollection<BluetoothDevice> boundSet = adapter.BondedDevices;
                BluetoothDevice btDevice1 = boundSet.ElementAt(1);
                btSocket = btDevice1.CreateRfcommSocketToServiceRecord(UUID.FromString("00001101-0000-1000-8000-00805F9B34FB"));
                adapter.CancelDiscovery();
                    btSocket.Connect();
                    txtStatus.Text = "Galaxy J7 Prime Connected";
                    btnConnect.Enabled = false;
            }
            catch (Exception ex)
            {
                txtStatus.Text = ex.Message;
                Toast.MakeText(this, ex.Message, ToastLength.Short);
            }
    

    Kindly help me to resolve out.My connection is not established because of this I am mot able to move ahead..

  • Hi. I dev sync bt stack with timeout(android only).
    See my github profile mksmbrtsh, project "TestBth Sync". I'm not allow put link to this forum. Good luck!
  • YonatanSadeYonatanSade Member

    For whose that are still wondering what to do, this worked to me.
    Here is a function that implement timeout and read the response into byte array:

            public int SendCommandGetResponse(byte[] command, byte[] response, int timeout, ref BluetoothSocket bluetoothSocket)
            {
                response = null;
    
                byte[] buffer = new byte[1000];
    
                bluetoothSocket.OutputStream.Flush();
                bluetoothSocket.InputStream.Flush();
    
                try
                {
                    bluetoothSocket.OutputStream.Write(command, 0, command.Length);
                }
                catch (System.Exception)
                {
                    return -1;
                }
    
                DataInputStream dataInputStream = new DataInputStream(bluetoothSocket.InputStream);
    
                int counter;
                int byteRead = 0;
                bool endOfPacket = false;
                while (endOfPacket == false)
                {
                    counter = timeout;
                    while (dataInputStream.Available() == 0)
                    {
                        Thread.Sleep(1);
                        counter--;
                        if (counter == 0)
                        {
                            endOfPacket = true;
                            break;
                        }
                    }
    
                    if (endOfPacket == false)
                    {
                        byteRead += dataInputStream.Read(buffer, byteRead, 1);
                    }
                }
    
                response = buffer.Take(byteRead).ToArray();
                return byteRead;
            }
    
Sign In or Register to comment.